Closes #575 - Added `SupportDataGenerator` object which generates data sent with support email. Format of the data is based on what Android has. - Support button is moved to settings from profile. - Support button opens mail composer.
This commit is contained in:
parent
a4d35b759f
commit
2a560dea8d
|
@ -320,6 +320,16 @@
|
||||||
3448CB3228E47666006ADEDB /* NotEnoughFreeSpaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */; };
|
3448CB3228E47666006ADEDB /* NotEnoughFreeSpaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */; };
|
||||||
3448CB3728E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */; };
|
3448CB3728E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */; };
|
||||||
346715A528E2027D0035F7C4 /* CheckCircleStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346715A428E2027D0035F7C4 /* CheckCircleStore.swift */; };
|
346715A528E2027D0035F7C4 /* CheckCircleStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346715A428E2027D0035F7C4 /* CheckCircleStore.swift */; };
|
||||||
|
3467319529AE265300974482 /* SupportDataGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319429AE265300974482 /* SupportDataGenerator.swift */; };
|
||||||
|
3467319629AE265300974482 /* SupportDataGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319429AE265300974482 /* SupportDataGenerator.swift */; };
|
||||||
|
3467319929AE374300974482 /* SupportDataGeneratorInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319829AE374300974482 /* SupportDataGeneratorInterface.swift */; };
|
||||||
|
3467319A29AE374300974482 /* SupportDataGeneratorInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319829AE374300974482 /* SupportDataGeneratorInterface.swift */; };
|
||||||
|
3467319C29AE374A00974482 /* SupportDataGeneratorLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319B29AE374A00974482 /* SupportDataGeneratorLiveKey.swift */; };
|
||||||
|
3467319D29AE374A00974482 /* SupportDataGeneratorLiveKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319B29AE374A00974482 /* SupportDataGeneratorLiveKey.swift */; };
|
||||||
|
3467319F29AE375000974482 /* SupportDataGeneratorTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319E29AE375000974482 /* SupportDataGeneratorTestKey.swift */; };
|
||||||
|
346731A029AE375000974482 /* SupportDataGeneratorTestKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3467319E29AE375000974482 /* SupportDataGeneratorTestKey.swift */; };
|
||||||
|
346731A229AE3A5100974482 /* UIMailDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346731A129AE3A5100974482 /* UIMailDialog.swift */; };
|
||||||
|
346731A329AE3A5100974482 /* UIMailDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346731A129AE3A5100974482 /* UIMailDialog.swift */; };
|
||||||
3469F18229ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3469F18129ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift */; };
|
3469F18229ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3469F18129ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift */; };
|
||||||
346D41E428DF0B8600963F36 /* CheckCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346D41E328DF0B8600963F36 /* CheckCircle.swift */; };
|
346D41E428DF0B8600963F36 /* CheckCircle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346D41E328DF0B8600963F36 /* CheckCircle.swift */; };
|
||||||
34BF09092927C98000222134 /* Memo+toString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BF09082927C98000222134 /* Memo+toString.swift */; };
|
34BF09092927C98000222134 /* Memo+toString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BF09082927C98000222134 /* Memo+toString.swift */; };
|
||||||
|
@ -645,6 +655,11 @@
|
||||||
3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFreeSpaceView.swift; sourceTree = "<group>"; };
|
3448CB3128E47666006ADEDB /* NotEnoughFreeSpaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFreeSpaceView.swift; sourceTree = "<group>"; };
|
||||||
3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFeeSpaceSnapshots.swift; sourceTree = "<group>"; };
|
3448CB3628E485CB006ADEDB /* NotEnoughFeeSpaceSnapshots.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotEnoughFeeSpaceSnapshots.swift; sourceTree = "<group>"; };
|
||||||
346715A428E2027D0035F7C4 /* CheckCircleStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckCircleStore.swift; sourceTree = "<group>"; };
|
346715A428E2027D0035F7C4 /* CheckCircleStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckCircleStore.swift; sourceTree = "<group>"; };
|
||||||
|
3467319429AE265300974482 /* SupportDataGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportDataGenerator.swift; sourceTree = "<group>"; };
|
||||||
|
3467319829AE374300974482 /* SupportDataGeneratorInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportDataGeneratorInterface.swift; sourceTree = "<group>"; };
|
||||||
|
3467319B29AE374A00974482 /* SupportDataGeneratorLiveKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportDataGeneratorLiveKey.swift; sourceTree = "<group>"; };
|
||||||
|
3467319E29AE375000974482 /* SupportDataGeneratorTestKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportDataGeneratorTestKey.swift; sourceTree = "<group>"; };
|
||||||
|
346731A129AE3A5100974482 /* UIMailDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIMailDialog.swift; sourceTree = "<group>"; };
|
||||||
3469F18129ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFlowFeatureFlagTests.swift; sourceTree = "<group>"; };
|
3469F18129ACD70500A07146 /* OnboardingFlowFeatureFlagTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingFlowFeatureFlagTests.swift; sourceTree = "<group>"; };
|
||||||
346D41E328DF0B8600963F36 /* CheckCircle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckCircle.swift; sourceTree = "<group>"; };
|
346D41E328DF0B8600963F36 /* CheckCircle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckCircle.swift; sourceTree = "<group>"; };
|
||||||
34BF09082927C98000222134 /* Memo+toString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Memo+toString.swift"; sourceTree = "<group>"; };
|
34BF09082927C98000222134 /* Memo+toString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Memo+toString.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -1173,6 +1188,17 @@
|
||||||
path = SendSnapshotTests;
|
path = SendSnapshotTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
3467319729AE36F000974482 /* SupportDataGenerator */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
3467319429AE265300974482 /* SupportDataGenerator.swift */,
|
||||||
|
3467319829AE374300974482 /* SupportDataGeneratorInterface.swift */,
|
||||||
|
3467319B29AE374A00974482 /* SupportDataGeneratorLiveKey.swift */,
|
||||||
|
3467319E29AE375000974482 /* SupportDataGeneratorTestKey.swift */,
|
||||||
|
);
|
||||||
|
path = SupportDataGenerator;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
346D41E228DF0B0900963F36 /* CheckCircle */ = {
|
346D41E228DF0B0900963F36 /* CheckCircle */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1464,6 +1490,7 @@
|
||||||
9E612C6D2987A96500D09B09 /* UIKitBridge */ = {
|
9E612C6D2987A96500D09B09 /* UIKitBridge */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
346731A129AE3A5100974482 /* UIMailDialog.swift */,
|
||||||
9E612C6E2987A9B100D09B09 /* UIShareDialog.swift */,
|
9E612C6E2987A9B100D09B09 /* UIShareDialog.swift */,
|
||||||
);
|
);
|
||||||
path = UIKitBridge;
|
path = UIKitBridge;
|
||||||
|
@ -1649,6 +1676,7 @@
|
||||||
9EB863A329239D95003D0F8B /* RecoveryPhraseRandomizer */,
|
9EB863A329239D95003D0F8B /* RecoveryPhraseRandomizer */,
|
||||||
9EB863B62923C539003D0F8B /* SDKSynchronizer */,
|
9EB863B62923C539003D0F8B /* SDKSynchronizer */,
|
||||||
9EB863B32923C465003D0F8B /* SecItem */,
|
9EB863B32923C465003D0F8B /* SecItem */,
|
||||||
|
3467319729AE36F000974482 /* SupportDataGenerator */,
|
||||||
9EB8639E29239891003D0F8B /* URIParser */,
|
9EB8639E29239891003D0F8B /* URIParser */,
|
||||||
9E153A7129216EBD00112F41 /* UserDefaults */,
|
9E153A7129216EBD00112F41 /* UserDefaults */,
|
||||||
9EB863B72923C55A003D0F8B /* UserPreferencesStorage */,
|
9EB863B72923C55A003D0F8B /* UserPreferencesStorage */,
|
||||||
|
@ -2557,6 +2585,7 @@
|
||||||
0D26AEA5299E8196005260EE /* TransactionSendingView.swift in Sources */,
|
0D26AEA5299E8196005260EE /* TransactionSendingView.swift in Sources */,
|
||||||
0D26AEA6299E8196005260EE /* WalletEventsFlowView.swift in Sources */,
|
0D26AEA6299E8196005260EE /* WalletEventsFlowView.swift in Sources */,
|
||||||
0D26AEA7299E8196005260EE /* CaptureDeviceLiveKey.swift in Sources */,
|
0D26AEA7299E8196005260EE /* CaptureDeviceLiveKey.swift in Sources */,
|
||||||
|
3467319A29AE374300974482 /* SupportDataGeneratorInterface.swift in Sources */,
|
||||||
0D26AEA8299E8196005260EE /* AudioServicesInterface.swift in Sources */,
|
0D26AEA8299E8196005260EE /* AudioServicesInterface.swift in Sources */,
|
||||||
0D26AEA9299E8196005260EE /* NotificationCenterTest.swift in Sources */,
|
0D26AEA9299E8196005260EE /* NotificationCenterTest.swift in Sources */,
|
||||||
0D26AEAA299E8196005260EE /* CrashReporterLiveKey.swift in Sources */,
|
0D26AEAA299E8196005260EE /* CrashReporterLiveKey.swift in Sources */,
|
||||||
|
@ -2605,15 +2634,18 @@
|
||||||
0D26AED3299E8196005260EE /* SyncStatusSnapshot.swift in Sources */,
|
0D26AED3299E8196005260EE /* SyncStatusSnapshot.swift in Sources */,
|
||||||
0D26AED4299E8196005260EE /* SecantButtonStyles.swift in Sources */,
|
0D26AED4299E8196005260EE /* SecantButtonStyles.swift in Sources */,
|
||||||
0D26AED5299E8196005260EE /* RecoveryPhraseBackupFailedView.swift in Sources */,
|
0D26AED5299E8196005260EE /* RecoveryPhraseBackupFailedView.swift in Sources */,
|
||||||
|
346731A029AE375000974482 /* SupportDataGeneratorTestKey.swift in Sources */,
|
||||||
0D26AED6299E8196005260EE /* UserPreferencesStorageInterface.swift in Sources */,
|
0D26AED6299E8196005260EE /* UserPreferencesStorageInterface.swift in Sources */,
|
||||||
0D26AED7299E8196005260EE /* DiskSpaceCheckerMocks.swift in Sources */,
|
0D26AED7299E8196005260EE /* DiskSpaceCheckerMocks.swift in Sources */,
|
||||||
0D26AED8299E8196005260EE /* DropDelegate.swift in Sources */,
|
0D26AED8299E8196005260EE /* DropDelegate.swift in Sources */,
|
||||||
0D26AED9299E8196005260EE /* LocalAuthenticationLiveKey.swift in Sources */,
|
0D26AED9299E8196005260EE /* LocalAuthenticationLiveKey.swift in Sources */,
|
||||||
0D26AEDA299E8196005260EE /* ImportSeedEditor.swift in Sources */,
|
0D26AEDA299E8196005260EE /* ImportSeedEditor.swift in Sources */,
|
||||||
0D26AEDB299E8196005260EE /* ProfileStore.swift in Sources */,
|
0D26AEDB299E8196005260EE /* ProfileStore.swift in Sources */,
|
||||||
|
3467319629AE265300974482 /* SupportDataGenerator.swift in Sources */,
|
||||||
0D26AEDC299E8196005260EE /* CheckCircle.swift in Sources */,
|
0D26AEDC299E8196005260EE /* CheckCircle.swift in Sources */,
|
||||||
0D26AEDD299E8196005260EE /* LogStore.swift in Sources */,
|
0D26AEDD299E8196005260EE /* LogStore.swift in Sources */,
|
||||||
0D26AEDE299E8196005260EE /* RecoveryPhraseRandomizer.swift in Sources */,
|
0D26AEDE299E8196005260EE /* RecoveryPhraseRandomizer.swift in Sources */,
|
||||||
|
3467319D29AE374A00974482 /* SupportDataGeneratorLiveKey.swift in Sources */,
|
||||||
0D26AEDF299E8196005260EE /* FileManagerTestKey.swift in Sources */,
|
0D26AEDF299E8196005260EE /* FileManagerTestKey.swift in Sources */,
|
||||||
0D26AEE0299E8196005260EE /* SecItemLive.swift in Sources */,
|
0D26AEE0299E8196005260EE /* SecItemLive.swift in Sources */,
|
||||||
0D26AEE1299E8196005260EE /* CircularFrameBadge.swift in Sources */,
|
0D26AEE1299E8196005260EE /* CircularFrameBadge.swift in Sources */,
|
||||||
|
@ -2733,6 +2765,7 @@
|
||||||
0D26AF52299E8196005260EE /* LogsHandlerTest.swift in Sources */,
|
0D26AF52299E8196005260EE /* LogsHandlerTest.swift in Sources */,
|
||||||
0D26AF53299E8196005260EE /* TextFieldFooter.swift in Sources */,
|
0D26AF53299E8196005260EE /* TextFieldFooter.swift in Sources */,
|
||||||
0D26AF54299E8196005260EE /* CrashReportingInterface.swift in Sources */,
|
0D26AF54299E8196005260EE /* CrashReportingInterface.swift in Sources */,
|
||||||
|
346731A329AE3A5100974482 /* UIMailDialog.swift in Sources */,
|
||||||
0D26AF55299E8196005260EE /* ProfileView.swift in Sources */,
|
0D26AF55299E8196005260EE /* ProfileView.swift in Sources */,
|
||||||
0D26AF56299E8196005260EE /* ScanStore.swift in Sources */,
|
0D26AF56299E8196005260EE /* ScanStore.swift in Sources */,
|
||||||
0D26AF57299E8196005260EE /* NumberFormatterTestKey.swift in Sources */,
|
0D26AF57299E8196005260EE /* NumberFormatterTestKey.swift in Sources */,
|
||||||
|
@ -2781,6 +2814,7 @@
|
||||||
34DA414728E4385800F8CC61 /* TransactionSendingView.swift in Sources */,
|
34DA414728E4385800F8CC61 /* TransactionSendingView.swift in Sources */,
|
||||||
F96B41E9273B501F0021B49A /* WalletEventsFlowView.swift in Sources */,
|
F96B41E9273B501F0021B49A /* WalletEventsFlowView.swift in Sources */,
|
||||||
9EBDF96E291ECED4000A1A05 /* CaptureDeviceLiveKey.swift in Sources */,
|
9EBDF96E291ECED4000A1A05 /* CaptureDeviceLiveKey.swift in Sources */,
|
||||||
|
3467319929AE374300974482 /* SupportDataGeneratorInterface.swift in Sources */,
|
||||||
9EBDF968291ECDA2000A1A05 /* AudioServicesInterface.swift in Sources */,
|
9EBDF968291ECDA2000A1A05 /* AudioServicesInterface.swift in Sources */,
|
||||||
9EB863BD2923C704003D0F8B /* NotificationCenterTest.swift in Sources */,
|
9EB863BD2923C704003D0F8B /* NotificationCenterTest.swift in Sources */,
|
||||||
0D26103E298C3FA600CC9DE9 /* CrashReporterLiveKey.swift in Sources */,
|
0D26103E298C3FA600CC9DE9 /* CrashReporterLiveKey.swift in Sources */,
|
||||||
|
@ -2829,15 +2863,18 @@
|
||||||
9E66122C2877188700C75B70 /* SyncStatusSnapshot.swift in Sources */,
|
9E66122C2877188700C75B70 /* SyncStatusSnapshot.swift in Sources */,
|
||||||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */,
|
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */,
|
||||||
0DDB6A5127737D4A0012A410 /* RecoveryPhraseBackupFailedView.swift in Sources */,
|
0DDB6A5127737D4A0012A410 /* RecoveryPhraseBackupFailedView.swift in Sources */,
|
||||||
|
3467319F29AE375000974482 /* SupportDataGeneratorTestKey.swift in Sources */,
|
||||||
0D63170029919970007D873F /* UserPreferencesStorageInterface.swift in Sources */,
|
0D63170029919970007D873F /* UserPreferencesStorageInterface.swift in Sources */,
|
||||||
9EBDF94D291D773A000A1A05 /* DiskSpaceCheckerMocks.swift in Sources */,
|
9EBDF94D291D773A000A1A05 /* DiskSpaceCheckerMocks.swift in Sources */,
|
||||||
0D6D628B276A528E002FB4CC /* DropDelegate.swift in Sources */,
|
0D6D628B276A528E002FB4CC /* DropDelegate.swift in Sources */,
|
||||||
9EBDF986291F91EF000A1A05 /* LocalAuthenticationLiveKey.swift in Sources */,
|
9EBDF986291F91EF000A1A05 /* LocalAuthenticationLiveKey.swift in Sources */,
|
||||||
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */,
|
9E2DF99D27CF704D00649636 /* ImportSeedEditor.swift in Sources */,
|
||||||
F9971A5327680DD000A2DB75 /* ProfileStore.swift in Sources */,
|
F9971A5327680DD000A2DB75 /* ProfileStore.swift in Sources */,
|
||||||
|
3467319529AE265300974482 /* SupportDataGenerator.swift in Sources */,
|
||||||
346D41E428DF0B8600963F36 /* CheckCircle.swift in Sources */,
|
346D41E428DF0B8600963F36 /* CheckCircle.swift in Sources */,
|
||||||
9E0F5745297EBA1B005304FA /* LogStore.swift in Sources */,
|
9E0F5745297EBA1B005304FA /* LogStore.swift in Sources */,
|
||||||
9EB863AA29239EB2003D0F8B /* RecoveryPhraseRandomizer.swift in Sources */,
|
9EB863AA29239EB2003D0F8B /* RecoveryPhraseRandomizer.swift in Sources */,
|
||||||
|
3467319C29AE374A00974482 /* SupportDataGeneratorLiveKey.swift in Sources */,
|
||||||
9EB863C52923C8AF003D0F8B /* FileManagerTestKey.swift in Sources */,
|
9EB863C52923C8AF003D0F8B /* FileManagerTestKey.swift in Sources */,
|
||||||
9EB863BF2923C72C003D0F8B /* SecItemLive.swift in Sources */,
|
9EB863BF2923C72C003D0F8B /* SecItemLive.swift in Sources */,
|
||||||
669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */,
|
669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */,
|
||||||
|
@ -2957,6 +2994,7 @@
|
||||||
9E612C7629880FC900D09B09 /* LogsHandlerTest.swift in Sources */,
|
9E612C7629880FC900D09B09 /* LogsHandlerTest.swift in Sources */,
|
||||||
2EDA07A227EDE1AE00D6F09B /* TextFieldFooter.swift in Sources */,
|
2EDA07A227EDE1AE00D6F09B /* TextFieldFooter.swift in Sources */,
|
||||||
0D26103C298C3E4800CC9DE9 /* CrashReportingInterface.swift in Sources */,
|
0D26103C298C3E4800CC9DE9 /* CrashReportingInterface.swift in Sources */,
|
||||||
|
346731A229AE3A5100974482 /* UIMailDialog.swift in Sources */,
|
||||||
F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */,
|
F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */,
|
||||||
F9971A6027680DF600A2DB75 /* ScanStore.swift in Sources */,
|
F9971A6027680DF600A2DB75 /* ScanStore.swift in Sources */,
|
||||||
9EB863952922D036003D0F8B /* NumberFormatterTestKey.swift in Sources */,
|
9EB863952922D036003D0F8B /* NumberFormatterTestKey.swift in Sources */,
|
||||||
|
|
|
@ -0,0 +1,186 @@
|
||||||
|
//
|
||||||
|
// SupportDataGenerator.swift
|
||||||
|
// secant
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 28.02.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AVFoundation
|
||||||
|
import Foundation
|
||||||
|
import LocalAuthentication
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
struct SupportData: Equatable {
|
||||||
|
let toAddress: String
|
||||||
|
let subject: String
|
||||||
|
let message: String
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SupportDataGenerator {
|
||||||
|
static func generate() -> SupportData {
|
||||||
|
let items: [SupportDataGeneratorItem] = [
|
||||||
|
TimeItem(),
|
||||||
|
AppVersionItem(),
|
||||||
|
SystemVersionItem(),
|
||||||
|
DeviceModelItem(),
|
||||||
|
LocaleItem(),
|
||||||
|
FreeDiskSpaceItem(),
|
||||||
|
PermissionsItems()
|
||||||
|
]
|
||||||
|
|
||||||
|
let message = items
|
||||||
|
.map { $0.generate() }
|
||||||
|
.flatMap { $0 }
|
||||||
|
.map { "\($0.0): \($0.1)" }
|
||||||
|
.joined(separator: "\n")
|
||||||
|
|
||||||
|
return SupportData(toAddress: "support@electriccoin.co", subject: "sECCant", message: message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private protocol SupportDataGeneratorItem {
|
||||||
|
func generate() -> [(String, String)]
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct TimeItem: SupportDataGeneratorItem {
|
||||||
|
private enum Constants {
|
||||||
|
static let timeKey = "Current time"
|
||||||
|
}
|
||||||
|
|
||||||
|
let dateFormatter: DateFormatter
|
||||||
|
|
||||||
|
init() {
|
||||||
|
dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "yyyy-MM-dd hh:mm:ss a ZZZZ"
|
||||||
|
dateFormatter.locale = Locale(identifier: "en_US")
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() -> [(String, String)] {
|
||||||
|
return [(Constants.timeKey, dateFormatter.string(from: Date()))]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct AppVersionItem: SupportDataGeneratorItem {
|
||||||
|
private enum Constants {
|
||||||
|
static let bundleIdentifierKey = "App identifier"
|
||||||
|
static let versionKey = "App version"
|
||||||
|
static let unknownVersion = "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() -> [(String, String)] {
|
||||||
|
let bundle = Bundle.main
|
||||||
|
guard let infoDict = bundle.infoDictionary else { return [(Constants.versionKey, Constants.unknownVersion)] }
|
||||||
|
|
||||||
|
var data: [(String, String)] = []
|
||||||
|
if let bundleIdentifier = bundle.bundleIdentifier {
|
||||||
|
data.append((Constants.bundleIdentifierKey, bundleIdentifier))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let build = infoDict["CFBundleVersion"] as? String, let version = infoDict["CFBundleShortVersionString"] as? String {
|
||||||
|
data.append((Constants.versionKey, "\(version) (\(build))"))
|
||||||
|
} else {
|
||||||
|
data.append((Constants.versionKey, Constants.unknownVersion))
|
||||||
|
}
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct SystemVersionItem: SupportDataGeneratorItem {
|
||||||
|
private enum Constants {
|
||||||
|
static let systemVersionKey = "iOS version"
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() -> [(String, String)] {
|
||||||
|
return [(Constants.systemVersionKey, UIDevice.current.systemVersion)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct DeviceModelItem: SupportDataGeneratorItem {
|
||||||
|
private enum Constants {
|
||||||
|
static let deviceModelKey = "Device"
|
||||||
|
static let unknownDevice = "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() -> [(String, String)] {
|
||||||
|
var systemInfo = utsname()
|
||||||
|
uname(&systemInfo)
|
||||||
|
var readModel: String?
|
||||||
|
withUnsafePointer(to: &systemInfo.machine.0) { charPointer in
|
||||||
|
readModel = String(cString: charPointer, encoding: .ascii)
|
||||||
|
}
|
||||||
|
|
||||||
|
let model = readModel ?? Constants.unknownDevice
|
||||||
|
return [(Constants.deviceModelKey, model)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct LocaleItem: SupportDataGeneratorItem {
|
||||||
|
private enum Constants {
|
||||||
|
static let localKey = "Locale"
|
||||||
|
static let groupingSeparatorKey = "Currency grouping separato"
|
||||||
|
static let decimalSeparatorKey = "Currency decimal separator"
|
||||||
|
static let unknownSeparator = "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() -> [(String, String)] {
|
||||||
|
let locale = Locale.current
|
||||||
|
|
||||||
|
return [
|
||||||
|
(Constants.localKey, locale.identifier),
|
||||||
|
(Constants.groupingSeparatorKey, locale.groupingSeparator ?? Constants.unknownSeparator),
|
||||||
|
(Constants.decimalSeparatorKey, locale.decimalSeparator ?? Constants.unknownSeparator)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct FreeDiskSpaceItem: SupportDataGeneratorItem {
|
||||||
|
private enum Constants {
|
||||||
|
static let freeDiskSpaceKey = "Usable storage"
|
||||||
|
static let freeDiskSpaceUnknown = "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() -> [(String, String)] {
|
||||||
|
let freeDiskSpace: String
|
||||||
|
|
||||||
|
let fileURL = URL(fileURLWithPath: NSHomeDirectory())
|
||||||
|
do {
|
||||||
|
let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
|
||||||
|
if let freeSpace = values.volumeAvailableCapacityForImportantUsage {
|
||||||
|
freeDiskSpace = "\(freeSpace / 1024 / 1024) MB"
|
||||||
|
} else {
|
||||||
|
freeDiskSpace = Constants.freeDiskSpaceUnknown
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
LoggerProxy.debug("Can't get free disk space: \(error)")
|
||||||
|
freeDiskSpace = Constants.freeDiskSpaceUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
return [(Constants.freeDiskSpaceKey, freeDiskSpace)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PermissionsItems: SupportDataGeneratorItem {
|
||||||
|
private enum Constants {
|
||||||
|
static let permissionsKey = "Permissions"
|
||||||
|
static let cameraPermKey = "Camera access"
|
||||||
|
static let faceIDAvailable = "FaceID available"
|
||||||
|
static let touchIDAvailable = "TouchID available"
|
||||||
|
static let yesText = "yes"
|
||||||
|
static let noText = "no"
|
||||||
|
}
|
||||||
|
|
||||||
|
func generate() -> [(String, String)] {
|
||||||
|
let cameraAuthorized = AVCaptureDevice.authorizationStatus(for: .video) == .authorized
|
||||||
|
|
||||||
|
let bioAuthContext = LAContext()
|
||||||
|
let biometricAuthAvailable = bioAuthContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil)
|
||||||
|
|
||||||
|
return [
|
||||||
|
(Constants.permissionsKey, ""),
|
||||||
|
(Constants.cameraPermKey, cameraAuthorized ? Constants.yesText : Constants.noText),
|
||||||
|
(Constants.faceIDAvailable, biometricAuthAvailable && bioAuthContext.biometryType == .faceID ? Constants.yesText : Constants.noText),
|
||||||
|
(Constants.touchIDAvailable, biometricAuthAvailable && bioAuthContext.biometryType == .touchID ? Constants.yesText : Constants.noText)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// SupportDataGeneratorInterface.swift
|
||||||
|
// secant
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 28.02.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ComposableArchitecture
|
||||||
|
|
||||||
|
extension DependencyValues {
|
||||||
|
var supportDataGenerator: SupportDataGeneratorClient {
|
||||||
|
get { self[SupportDataGeneratorClient.self] }
|
||||||
|
set { self[SupportDataGeneratorClient.self] = newValue }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SupportDataGeneratorClient {
|
||||||
|
let generate: () -> SupportData
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// SupportDataGeneratorLiveKey.swift
|
||||||
|
// secant
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 28.02.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ComposableArchitecture
|
||||||
|
|
||||||
|
extension SupportDataGeneratorClient: DependencyKey {
|
||||||
|
static let liveValue = Self(
|
||||||
|
generate: { SupportDataGenerator.generate() }
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// SupportDataGeneratorTestKey.swift
|
||||||
|
// secant
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 28.02.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ComposableArchitecture
|
||||||
|
import XCTestDynamicOverlay
|
||||||
|
|
||||||
|
extension SupportDataGeneratorClient: TestDependencyKey {
|
||||||
|
static let testValue = Self(
|
||||||
|
generate: XCTUnimplemented("\(Self.self).generate")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension SupportDataGeneratorClient {
|
||||||
|
static let noOp = Self(
|
||||||
|
generate: { SupportData(toAddress: "", subject: "", message: "") }
|
||||||
|
)
|
||||||
|
}
|
|
@ -37,14 +37,6 @@ struct ProfileView: View {
|
||||||
.frame(height: 50)
|
.frame(height: 50)
|
||||||
.padding(EdgeInsets(top: 30, leading: 30, bottom: 20, trailing: 30))
|
.padding(EdgeInsets(top: 30, leading: 30, bottom: 20, trailing: 30))
|
||||||
|
|
||||||
Button(
|
|
||||||
action: { },
|
|
||||||
label: { Text("Support") }
|
|
||||||
)
|
|
||||||
.primaryButtonStyle
|
|
||||||
.frame(height: 50)
|
|
||||||
.padding(EdgeInsets(top: 0, leading: 30, bottom: 20, trailing: 30))
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import ComposableArchitecture
|
import ComposableArchitecture
|
||||||
|
import MessageUI
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
typealias SettingsStore = Store<SettingsReducer.State, SettingsReducer.Action>
|
typealias SettingsStore = Store<SettingsReducer.State, SettingsReducer.Action>
|
||||||
|
@ -10,13 +11,14 @@ struct SettingsReducer: ReducerProtocol {
|
||||||
case backupPhrase
|
case backupPhrase
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BindingState var alert: AlertState<SettingsReducer.Action>?
|
||||||
var destination: Destination?
|
var destination: Destination?
|
||||||
var exportLogsDisabled = false
|
var exportLogsDisabled = false
|
||||||
|
@BindingState var isCrashReportingOn: Bool
|
||||||
var isSharingLogs = false
|
var isSharingLogs = false
|
||||||
var phraseDisplayState: RecoveryPhraseDisplayReducer.State
|
var phraseDisplayState: RecoveryPhraseDisplayReducer.State
|
||||||
var rescanDialog: ConfirmationDialogState<SettingsReducer.Action>?
|
var rescanDialog: ConfirmationDialogState<SettingsReducer.Action>?
|
||||||
|
var supportData: SupportData?
|
||||||
@BindingState var isCrashReportingOn: Bool
|
|
||||||
|
|
||||||
var tempSDKDir: URL {
|
var tempSDKDir: URL {
|
||||||
let tempDir = FileManager.default.temporaryDirectory
|
let tempDir = FileManager.default.temporaryDirectory
|
||||||
|
@ -42,6 +44,7 @@ struct SettingsReducer: ReducerProtocol {
|
||||||
case backupWalletAccessRequest
|
case backupWalletAccessRequest
|
||||||
case binding(BindingAction<SettingsReducer.State>)
|
case binding(BindingAction<SettingsReducer.State>)
|
||||||
case cancelRescan
|
case cancelRescan
|
||||||
|
case dismissAlert
|
||||||
case exportLogs
|
case exportLogs
|
||||||
case fullRescan
|
case fullRescan
|
||||||
case logsExported
|
case logsExported
|
||||||
|
@ -50,8 +53,10 @@ struct SettingsReducer: ReducerProtocol {
|
||||||
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
|
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
|
||||||
case quickRescan
|
case quickRescan
|
||||||
case rescanBlockchain
|
case rescanBlockchain
|
||||||
case updateDestination(SettingsReducer.State.Destination?)
|
case sendSupportMail
|
||||||
|
case sendSupportMailFinished
|
||||||
case testCrashReporter // this will crash the app if live.
|
case testCrashReporter // this will crash the app if live.
|
||||||
|
case updateDestination(SettingsReducer.State.Destination?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Dependency(\.localAuthentication) var localAuthentication
|
@Dependency(\.localAuthentication) var localAuthentication
|
||||||
|
@ -102,6 +107,10 @@ struct SettingsReducer: ReducerProtocol {
|
||||||
state.rescanDialog = nil
|
state.rescanDialog = nil
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
|
case .dismissAlert:
|
||||||
|
state.alert = nil
|
||||||
|
return .none
|
||||||
|
|
||||||
case .exportLogs:
|
case .exportLogs:
|
||||||
state.exportLogsDisabled = true
|
state.exportLogsDisabled = true
|
||||||
return .run { [state] send in
|
return .run { [state] send in
|
||||||
|
@ -148,6 +157,26 @@ struct SettingsReducer: ReducerProtocol {
|
||||||
|
|
||||||
case .binding:
|
case .binding:
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
|
case .sendSupportMail:
|
||||||
|
if MFMailComposeViewController.canSendMail() {
|
||||||
|
state.supportData = SupportDataGenerator.generate()
|
||||||
|
} else {
|
||||||
|
state.alert = AlertState(
|
||||||
|
title: TextState("Can't send email"),
|
||||||
|
message: TextState("""
|
||||||
|
It looks like that you don't have any email account configured on your device. Therefore it's not possible to send a support \
|
||||||
|
email.
|
||||||
|
"""),
|
||||||
|
dismissButton: .default(TextState("Ok"), action: .send(.sendSupportMailFinished))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return .none
|
||||||
|
|
||||||
|
case .sendSupportMailFinished:
|
||||||
|
state.supportData = nil
|
||||||
|
return .none
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +219,10 @@ extension SettingsStore {
|
||||||
|
|
||||||
extension SettingsReducer.State {
|
extension SettingsReducer.State {
|
||||||
static let placeholder = SettingsReducer.State(
|
static let placeholder = SettingsReducer.State(
|
||||||
|
isCrashReportingOn: true,
|
||||||
phraseDisplayState: RecoveryPhraseDisplayReducer.State(
|
phraseDisplayState: RecoveryPhraseDisplayReducer.State(
|
||||||
phrase: .placeholder
|
phrase: .placeholder
|
||||||
),
|
)
|
||||||
isCrashReportingOn: true
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,14 @@ struct SettingsView: View {
|
||||||
)
|
)
|
||||||
.primaryButtonStyle
|
.primaryButtonStyle
|
||||||
.frame(height: 50)
|
.frame(height: 50)
|
||||||
|
|
||||||
|
Button(
|
||||||
|
action: { viewStore.send(.sendSupportMail) },
|
||||||
|
label: { Text("Send us feedback!") }
|
||||||
|
)
|
||||||
|
.primaryButtonStyle
|
||||||
|
.frame(height: 50)
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 30)
|
.padding(.horizontal, 30)
|
||||||
|
@ -64,6 +72,7 @@ struct SettingsView: View {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.onAppear { viewStore.send(.onAppear) }
|
.onAppear { viewStore.send(.onAppear) }
|
||||||
|
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||||
|
|
||||||
if viewStore.isSharingLogs {
|
if viewStore.isSharingLogs {
|
||||||
UIShareDialogView(
|
UIShareDialogView(
|
||||||
|
@ -75,6 +84,18 @@ struct SettingsView: View {
|
||||||
// so frame is set to 0 to not break SwiftUIs layout
|
// so frame is set to 0 to not break SwiftUIs layout
|
||||||
.frame(width: 0, height: 0)
|
.frame(width: 0, height: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let supportData = viewStore.supportData {
|
||||||
|
UIMailDialogView(
|
||||||
|
supportData: supportData,
|
||||||
|
completion: {
|
||||||
|
viewStore.send(.sendSupportMailFinished)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// UIMailDialogView only wraps MFMailComposeViewController presentation
|
||||||
|
// so frame is set to 0 to not break SwiftUIs layout
|
||||||
|
.frame(width: 0, height: 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
//
|
||||||
|
// UIMailDialog.swift
|
||||||
|
// secant
|
||||||
|
//
|
||||||
|
// Created by Michal Fousek on 28.02.2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import MessageUI
|
||||||
|
import UIKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
class UIMailDialog: UIView {
|
||||||
|
var completion: (() -> Void)?
|
||||||
|
|
||||||
|
required init?(coder aDecoder: NSCoder) {
|
||||||
|
super.init(coder: aDecoder)
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UIMailDialog {
|
||||||
|
func doInitialSetup(supportData: SupportData, completion: @escaping () -> Void) {
|
||||||
|
self.completion = completion
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
let mailVC = MFMailComposeViewController()
|
||||||
|
mailVC.mailComposeDelegate = self
|
||||||
|
|
||||||
|
// Configure the fields of the interface.
|
||||||
|
mailVC.setToRecipients([supportData.toAddress])
|
||||||
|
mailVC.setSubject(supportData.subject)
|
||||||
|
mailVC.setMessageBody("\n\n\(supportData.message)", isHTML: false)
|
||||||
|
|
||||||
|
let rootVC = UIApplication.shared.connectedScenes
|
||||||
|
.map { $0 as? UIWindowScene }
|
||||||
|
.compactMap { $0 }
|
||||||
|
.first?.windows.first?.rootViewController
|
||||||
|
|
||||||
|
rootVC?.present(
|
||||||
|
mailVC,
|
||||||
|
animated: true,
|
||||||
|
completion: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UIMailDialog: MFMailComposeViewControllerDelegate {
|
||||||
|
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
|
||||||
|
controller.dismiss(animated: true, completion: completion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UIMailDialogView: UIViewRepresentable {
|
||||||
|
let supportData: SupportData
|
||||||
|
let completion: () -> Void
|
||||||
|
|
||||||
|
func makeUIView(context: UIViewRepresentableContext<UIMailDialogView>) -> UIMailDialog {
|
||||||
|
let view = UIMailDialog()
|
||||||
|
view.doInitialSetup(supportData: supportData, completion: completion)
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateUIView(_ uiView: UIMailDialog, context: UIViewRepresentableContext<UIMailDialogView>) {
|
||||||
|
// We can leave it empty here because the view is just handler how to bridge UIKit's UIActivityViewController
|
||||||
|
// presentation into SwiftUI. The view itself is not visible, only instantiated, therefore no updates needed.
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias UIViewType = UIMailDialog
|
||||||
|
}
|
|
@ -46,8 +46,8 @@ class SettingsTests: XCTestCase {
|
||||||
|
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
initialState: SettingsReducer.State(
|
initialState: SettingsReducer.State(
|
||||||
phraseDisplayState: RecoveryPhraseDisplayReducer.State(phrase: nil),
|
isCrashReportingOn: false,
|
||||||
isCrashReportingOn: false
|
phraseDisplayState: RecoveryPhraseDisplayReducer.State(phrase: nil)
|
||||||
),
|
),
|
||||||
reducer: SettingsReducer()
|
reducer: SettingsReducer()
|
||||||
) { dependencies in
|
) { dependencies in
|
||||||
|
@ -103,6 +103,7 @@ class SettingsTests: XCTestCase {
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
initialState: SettingsReducer.State(
|
initialState: SettingsReducer.State(
|
||||||
destination: nil,
|
destination: nil,
|
||||||
|
isCrashReportingOn: false,
|
||||||
phraseDisplayState: .init(),
|
phraseDisplayState: .init(),
|
||||||
rescanDialog: .init(
|
rescanDialog: .init(
|
||||||
title: TextState("Rescan"),
|
title: TextState("Rescan"),
|
||||||
|
@ -112,8 +113,7 @@ class SettingsTests: XCTestCase {
|
||||||
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
||||||
.cancel(TextState("Cancel"))
|
.cancel(TextState("Cancel"))
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
isCrashReportingOn: false
|
|
||||||
),
|
),
|
||||||
reducer: SettingsReducer()
|
reducer: SettingsReducer()
|
||||||
)
|
)
|
||||||
|
@ -127,6 +127,7 @@ class SettingsTests: XCTestCase {
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
initialState: SettingsReducer.State(
|
initialState: SettingsReducer.State(
|
||||||
destination: nil,
|
destination: nil,
|
||||||
|
isCrashReportingOn: false,
|
||||||
phraseDisplayState: .init(),
|
phraseDisplayState: .init(),
|
||||||
rescanDialog: .init(
|
rescanDialog: .init(
|
||||||
title: TextState("Rescan"),
|
title: TextState("Rescan"),
|
||||||
|
@ -136,8 +137,7 @@ class SettingsTests: XCTestCase {
|
||||||
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
||||||
.cancel(TextState("Cancel"))
|
.cancel(TextState("Cancel"))
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
isCrashReportingOn: false
|
|
||||||
),
|
),
|
||||||
reducer: SettingsReducer()
|
reducer: SettingsReducer()
|
||||||
)
|
)
|
||||||
|
@ -151,6 +151,7 @@ class SettingsTests: XCTestCase {
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
initialState: SettingsReducer.State(
|
initialState: SettingsReducer.State(
|
||||||
destination: nil,
|
destination: nil,
|
||||||
|
isCrashReportingOn: false,
|
||||||
phraseDisplayState: .init(),
|
phraseDisplayState: .init(),
|
||||||
rescanDialog: .init(
|
rescanDialog: .init(
|
||||||
title: TextState("Rescan"),
|
title: TextState("Rescan"),
|
||||||
|
@ -160,8 +161,7 @@ class SettingsTests: XCTestCase {
|
||||||
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
||||||
.cancel(TextState("Cancel"))
|
.cancel(TextState("Cancel"))
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
isCrashReportingOn: false
|
|
||||||
),
|
),
|
||||||
reducer: SettingsReducer()
|
reducer: SettingsReducer()
|
||||||
)
|
)
|
||||||
|
@ -175,6 +175,7 @@ class SettingsTests: XCTestCase {
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
initialState: SettingsReducer.State(
|
initialState: SettingsReducer.State(
|
||||||
destination: nil,
|
destination: nil,
|
||||||
|
isCrashReportingOn: false,
|
||||||
phraseDisplayState: .init(),
|
phraseDisplayState: .init(),
|
||||||
rescanDialog: .init(
|
rescanDialog: .init(
|
||||||
title: TextState("Rescan"),
|
title: TextState("Rescan"),
|
||||||
|
@ -184,8 +185,7 @@ class SettingsTests: XCTestCase {
|
||||||
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
||||||
.cancel(TextState("Cancel"))
|
.cancel(TextState("Cancel"))
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
isCrashReportingOn: false
|
|
||||||
),
|
),
|
||||||
reducer: SettingsReducer()
|
reducer: SettingsReducer()
|
||||||
)
|
)
|
||||||
|
@ -206,6 +206,7 @@ class SettingsTests: XCTestCase {
|
||||||
let store = TestStore(
|
let store = TestStore(
|
||||||
initialState: SettingsReducer.State(
|
initialState: SettingsReducer.State(
|
||||||
destination: nil,
|
destination: nil,
|
||||||
|
isCrashReportingOn: false,
|
||||||
isSharingLogs: true,
|
isSharingLogs: true,
|
||||||
phraseDisplayState: .init(),
|
phraseDisplayState: .init(),
|
||||||
rescanDialog: .init(
|
rescanDialog: .init(
|
||||||
|
@ -216,8 +217,7 @@ class SettingsTests: XCTestCase {
|
||||||
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
.default(TextState("Full rescan"), action: .send(.fullRescan)),
|
||||||
.cancel(TextState("Cancel"))
|
.cancel(TextState("Cancel"))
|
||||||
]
|
]
|
||||||
),
|
)
|
||||||
isCrashReportingOn: false
|
|
||||||
),
|
),
|
||||||
reducer: SettingsReducer()
|
reducer: SettingsReducer()
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue