Compare commits
381 Commits
0.0.1-45-m
...
main
Author | SHA1 | Date |
---|---|---|
Lukas Korba | 4046b6c059 | |
Lukas Korba | dab345be26 | |
Andrea Kobrlova | 6da9845dec | |
Andrea Kobrlova | e5bdf8aaaf | |
Andrea Kobrlova | 4bb15d5977 | |
Andrea Kobrlova | 9723a811ef | |
Lukas Korba | b2911ff134 | |
Lukas Korba | 3fb36406a3 | |
Lukas Korba | b1d6ecf695 | |
Lukas Korba | 8af0d785c7 | |
Lukas Korba | 2e928e6ae5 | |
Lukas Korba | 7a307bf592 | |
Lukas Korba | 0ad73b905d | |
Lukas Korba | 6d8096c20e | |
Lukas Korba | d54675069b | |
Lukas Korba | c1b373dcec | |
Lukas Korba | 4145b5eb8f | |
Lukas Korba | ccf15f4c9f | |
Lukas Korba | 1d821455c8 | |
Lukas Korba | 766213023a | |
Lukas Korba | 0337b1b1e9 | |
Lukas Korba | a5bb3af11e | |
Lukas Korba | a49a5d7ca8 | |
Lukas Korba | 0c4ab9ae56 | |
Lukas Korba | cd71176185 | |
Lukas Korba | ad523860ca | |
Lukas Korba | 00b9e5903b | |
Lukas Korba | 4f037aaa6b | |
Lukas Korba | 95f4b3ba94 | |
Lukas Korba | 1d7d5426d4 | |
Lukas Korba | 5ac25b2bbb | |
Lukas Korba | 633aed4b4a | |
Lukas Korba | 89e5afc30e | |
Lukas Korba | 8a2694ed41 | |
Lukas Korba | 120479a3ea | |
Lukas Korba | eaf0a6322c | |
Lukas Korba | 98f79f17f3 | |
Lukas Korba | b776a51802 | |
Lukas Korba | 55283ffa1a | |
Lukas Korba | 02b479826e | |
Lukas Korba | 156dde9678 | |
Lukas Korba | 1cb9ad1465 | |
Lukas Korba | aa024e95f6 | |
Lukas Korba | 8e26014364 | |
Lukas Korba | 3f679d1aba | |
Lukas Korba | 534d246006 | |
Lukas Korba | bedf46bb61 | |
Lukas Korba | e0b371d947 | |
Lukas Korba | 5deec082b9 | |
Lukas Korba | eb83de4d8d | |
Lukas Korba | e5f5cbf31f | |
Lukas Korba | d43990a7b1 | |
Lukas Korba | 3c6ca1bde2 | |
Lukas Korba | 6e8db9feb8 | |
Lukas Korba | 2280e15a04 | |
Lukas Korba | 17e5721ddc | |
Lukas Korba | 55efc372dc | |
Lukas Korba | e2ea411b2c | |
Lukas Korba | 9efb5ecd6d | |
Lukas Korba | 6abf3bac93 | |
Lukas Korba | 5f08313c4b | |
Lukas Korba | e776584575 | |
Lukas Korba | c662157034 | |
Lukas Korba | 7fbee0082b | |
Michal Fousek | ca35256417 | |
Andrea Kobrlova | f77d154c08 | |
Lukas Korba | 1645d00aad | |
Lukas Korba | e4ec0ad6f5 | |
Lukas Korba | fd589ea959 | |
Lukas Korba | 3b41b52dc1 | |
Lukas Korba | 9a3f7a4756 | |
Lukas Korba | 0892676253 | |
Lukas Korba | 34db837127 | |
Lukas Korba | 52017ab435 | |
Lukas Korba | 6a8b0d5b50 | |
Lukas Korba | e5ec490421 | |
Lukas Korba | 7bbfde8133 | |
Lukas Korba | e883749f50 | |
Lukas Korba | e7bd2fd458 | |
Lukas Korba | 16d3499c30 | |
Lukas Korba | cd0fba7665 | |
Lukas Korba | c64e1ef21b | |
Lukas Korba | d46d0a4f94 | |
Lukas Korba | ecad037103 | |
Lukas Korba | 3d6ed24dd4 | |
Lukas Korba | 375def846b | |
Lukas Korba | d295e10bb9 | |
Lukas Korba | 7b3d214531 | |
Lukas Korba | c8454ccd9c | |
Lukas Korba | 2ebf9fb9d7 | |
Lukas Korba | efb05a5913 | |
Lukas Korba | 52a2f6b0a9 | |
Lukas Korba | ad1ba0f98f | |
Lukas Korba | ff5b6ce0ef | |
Lukas Korba | 1bc5d70e36 | |
Lukas Korba | d8f70a64ee | |
Lukas Korba | 6e054f5b52 | |
Lukas Korba | 3e68ed8e33 | |
Lukas Korba | f73b6dc9e1 | |
Lukas Korba | 215e745522 | |
Lukas Korba | ccb5b2936c | |
Lukas Korba | 9e4b27e585 | |
Lukas Korba | e235a84528 | |
Lukas Korba | 88f91380eb | |
Lukas Korba | 23379c069c | |
Lukas Korba | 9decc16ffa | |
Lukas Korba | 2755f3c2c0 | |
Lukas Korba | 93b44b0b7f | |
Lukas Korba | 936f461740 | |
Lukas Korba | cbb842c6f3 | |
Lukas Korba | a8847abae6 | |
Lukas Korba | be00165d3b | |
Lukas Korba | d50a576f82 | |
Lukas Korba | 31db61df25 | |
Lukas Korba | 10399c9c6c | |
Lukas Korba | 5b45efa0fd | |
Lukas Korba | eeb9a57254 | |
Lukas Korba | cdca45f10c | |
Lukas Korba | 0bb356f6b3 | |
Lukas Korba | a1fd4097c7 | |
Lukas Korba | da3687b9d1 | |
Lukas Korba | ecc65f9a83 | |
Lukas Korba | 6e6245dd64 | |
Lukas Korba | 98ff1d4043 | |
Lukas Korba | 3e6afc69a8 | |
Lukas Korba | 2e51a9d839 | |
Lukas Korba | 5d3fcdd094 | |
Lukas Korba | b269c9210e | |
Lukas Korba | 31d455f0ac | |
Lukas Korba | e20038c573 | |
Lukas Korba | bcca5eff08 | |
Lukas Korba | 66a8e670cd | |
Lukas Korba | 28a88a9a1e | |
Lukas Korba | d3adf88b3f | |
Lukas Korba | 0bfc256488 | |
Lukas Korba | ad05fdb17e | |
Lukas Korba | 5948947288 | |
Lukas Korba | 1a6f458834 | |
Lukas Korba | 14920b0ea9 | |
Lukas Korba | 111e16fe31 | |
Lukas Korba | f7b6d78d42 | |
Lukas Korba | 7939015132 | |
Lukas Korba | c525105f59 | |
Lukas Korba | 36013ce69b | |
Lukas Korba | 1886b5fc47 | |
Lukas Korba | ee83a5afe9 | |
Lukas Korba | 1bc7f3ca59 | |
Lukas Korba | 749dd7f5a8 | |
Lukas Korba | 22153c97a1 | |
Lukas Korba | c848e5f48c | |
Lukas Korba | 14093cd3ea | |
Lukas Korba | 0819cb6f92 | |
Lukas Korba | 5260ac7809 | |
Lukas Korba | 9961058da4 | |
Lukas Korba | 42a8cd8184 | |
Lukas Korba | b1b3619db6 | |
Lukas Korba | b3c0198d28 | |
Lukas Korba | 4a634dec7e | |
Lukas Korba | e1125cf29b | |
Lukas Korba | dd51b758a8 | |
Lukas Korba | a25bdbb55c | |
Lukas Korba | ef460b7b42 | |
Lukas Korba | 55950c07e5 | |
Lukas Korba | 2632c8aad4 | |
Lukas Korba | 9b08395bf8 | |
Lukas Korba | 609158023e | |
Lukas Korba | e8822d21c9 | |
Lukas Korba | abb8dcea29 | |
Lukas Korba | 746b6859a7 | |
Lukas Korba | 22fab58852 | |
Lukas Korba | b5a71c7bed | |
Lukas Korba | 6970b6ff60 | |
Lukas Korba | 557cae3552 | |
Lukas Korba | 487abbd9bf | |
Lukas Korba | 2ba8f26d0a | |
Lukas Korba | 99e1b12e7d | |
Lukas Korba | 21b01fca7d | |
Lukas Korba | ecc8ec9c1d | |
Lukas Korba | 6b94e1a8f6 | |
Lukas Korba | 45d7241d33 | |
Lukas Korba | f1c7df7768 | |
Lukas Korba | 6c83487da4 | |
Lukas Korba | 97dc8eea80 | |
Lukas Korba | 18ee995a42 | |
Lukas Korba | a83dfa73f7 | |
Lukas Korba | ab10520492 | |
Lukas Korba | a0a17c6d49 | |
Lukas Korba | c9f1e85c1f | |
Lukas Korba | 25197b1dc6 | |
Lukas Korba | ff5cc09941 | |
Lukas Korba | 039af8c863 | |
Lukas Korba | 6b6c586f01 | |
Lukas Korba | 774f5d294d | |
Lukas Korba | 5a96727b01 | |
Lukas Korba | 32b7afb867 | |
Lukas Korba | ef64496739 | |
Lukas Korba | 21cb72dfc9 | |
Lukas Korba | e494744fcc | |
Lukas Korba | 3460cf6f58 | |
Lukas Korba | 06cc8ed1c1 | |
Lukas Korba | 6b783cbbe5 | |
Lukas Korba | 5afe5fb1dd | |
Lukas Korba | 9d7d9badb6 | |
Lukas Korba | 33b94b517d | |
Lukas Korba | 4639e4fc84 | |
Lukas Korba | 21412a356b | |
Lukas Korba | 10eb66f1a2 | |
Lukas Korba | 9b683651cf | |
Lukas Korba | 48536e5fa0 | |
Lukas Korba | 0faa37c243 | |
Lukas Korba | b668b15f04 | |
Lukas Korba | 783ed20c20 | |
Lukas Korba | 82fd0e043f | |
Lukas Korba | 8498cff744 | |
Lukas Korba | 5d078035f4 | |
Lukas Korba | 8372df6f1e | |
Lukas Korba | 924e318be3 | |
Lukas Korba | ec6e082938 | |
Lukas Korba | f7f5bcfedd | |
Lukas Korba | 0919584b81 | |
Lukas Korba | 9aa28d39b8 | |
Lukas Korba | 70631cc995 | |
Lukas Korba | 79648f59af | |
Lukas Korba | 1f39ce2423 | |
Lukas Korba | a64815c178 | |
Lukas Korba | 05364dc3c3 | |
Lukas Korba | 760243581f | |
Lukas Korba | f546c9d8f5 | |
Lukas Korba | f0c4759e0c | |
Kris Nuttycombe | 06355da1b4 | |
Lukas Korba | cef25b79cf | |
Kris Nuttycombe | 54fdc0cd9e | |
Lukas Korba | 4231fd321a | |
Kris Nuttycombe | f1a63e37f1 | |
Lukas Korba | 6f03d91bc3 | |
Lukas Korba | 8ebd310798 | |
Lukas Korba | 79ab841f75 | |
Lukas Korba | b6248fdd3c | |
Kris Nuttycombe | 96292825bf | |
Lukas Korba | a4fc0743c6 | |
Lukas Korba | 777aab54d5 | |
Lukas Korba | b801ac72d7 | |
Lukas Korba | 1d60dd3275 | |
Lukas Korba | 79205018a5 | |
Lukas Korba | 9ed49c9a29 | |
Kris Nuttycombe | 076d445597 | |
Lukas Korba | 88715ded04 | |
Lukas Korba | bc3db29ee0 | |
Lukas Korba | 5c1898f5a7 | |
Lukas Korba | eb36c6db3e | |
Lukas Korba | ad4ac13e86 | |
Kris Nuttycombe | e27e4ed34d | |
Lukas Korba | 8b53ebfc34 | |
Lukas Korba | 26de9e250b | |
Lukas Korba | 4f3a5f7270 | |
Lukas Korba | 4f06f83274 | |
Lukas Korba | 1d8ceb138b | |
Lukas Korba | f7c4a83d72 | |
Kris Nuttycombe | 26d6be7773 | |
Lukas Korba | c76322c0fb | |
Lukas Korba | 4ab2ca0e7c | |
Lukas Korba | a8a68852d3 | |
Lukas Korba | 14c5057eff | |
Kris Nuttycombe | 29835e085b | |
Lukas Korba | aa726aa9e3 | |
Kris Nuttycombe | 23ee03c208 | |
Kris Nuttycombe | 028af83616 | |
Lukas Korba | 50c603278a | |
Lukas Korba | e9d8e0fbbb | |
Lukas Korba | 49de5f2e3e | |
Lukas Korba | 34f0077604 | |
Lukas Korba | 3fa10e5147 | |
Lukas Korba | 74a2936b26 | |
Kris Nuttycombe | 38720c54d1 | |
Lukas Korba | c15b9558b8 | |
Kris Nuttycombe | a2d3246a24 | |
Lukas Korba | b4dc72d511 | |
Lukas Korba | c0d34224c4 | |
Lukas Korba | 3689e461cd | |
Lukas Korba | 72c34db59d | |
Lukas Korba | 44510ac88d | |
Kris Nuttycombe | e7db6a9050 | |
Lukas Korba | 9f4243b475 | |
Lukas Korba | 2d4ddd72c6 | |
Lukas Korba | 86007d449a | |
Lukas Korba | 9827e9aff9 | |
Lukas Korba | c1190c782e | |
Lukas Korba | fc4f6ad7f9 | |
Lukas Korba | 1e0c82e15d | |
Kris Nuttycombe | 3fcdbd4a2e | |
Kris Nuttycombe | e8a5d02395 | |
Lukas Korba | 5ad02e0c6b | |
Lukas Korba | 4fb80ed89f | |
Lukas Korba | 7c5022a5df | |
Lukas Korba | e33ee405ee | |
Lukas Korba | e1a5fa9778 | |
Kris Nuttycombe | c98ec53940 | |
Lukas Korba | 83e5f4fb11 | |
Lukas Korba | ebbf2520ad | |
Lukas Korba | bbd8da45d6 | |
Kris Nuttycombe | 9586bcbb60 | |
Kris Nuttycombe | 30eabdf589 | |
Lukas Korba | feb4ab4eaf | |
Lukas Korba | 78f230a768 | |
Lukas Korba | 9839f3e34e | |
Lukas Korba | a73a57aee2 | |
Lukas Korba | 9b2463a370 | |
Lukas Korba | faec526e15 | |
Lukas Korba | 59e0a68da5 | |
Lukas Korba | 0330f0e7e9 | |
Lukas Korba | 4913c60741 | |
Lukas Korba | 1de13698d8 | |
Lukas Korba | 0206641fc6 | |
Lukas Korba | ae2c18006d | |
Lukas Korba | de0c954dd7 | |
Lukas Korba | 5fe923f91d | |
Matthew Watt | 9fc08a221e | |
Lukas Korba | 60f8c6ae5d | |
Lukas Korba | d972a7834b | |
Lukas Korba | 2aadd2870a | |
Lukas Korba | f1de69f10e | |
Lukas Korba | 896f4532a1 | |
Lukas Korba | 0d5904e30c | |
Lukas Korba | e3a312ee1a | |
Lukas Korba | 9b77a57a5f | |
Matthew Watt | 2e4c526272 | |
Lukas Korba | 561ccc0689 | |
Lukas Korba | e2502075e0 | |
Lukas Korba | dbc6316766 | |
Lukas Korba | 7e9f8c3170 | |
Lukas Korba | c8546376db | |
Lukas Korba | 7ed4d1bfcf | |
Lukas Korba | 7b7ef3b087 | |
Lukas Korba | 04d4c363d4 | |
Lukas Korba | 49f7afd56a | |
Lukas Korba | 3cfba64f2a | |
Francisco Gindre | 31d05d914b | |
Francisco Gindre | d10f594782 | |
Lukas Korba | 403d60bf9f | |
Lukas Korba | b142609af9 | |
Francisco Gindre | b204c42a13 | |
Francisco Gindre | 44039f7648 | |
Francisco Gindre | a4e377e0d1 | |
Lukas Korba | c143f4b31d | |
Francisco Gindre | 647eeea7aa | |
Lukas Korba | 041a630412 | |
Lukas Korba | fe1e7b758c | |
Lukas Korba | a727f49817 | |
Lukas Korba | 36d2090654 | |
Michal Fousek | c61b406372 | |
Lukas Korba | ef26c835c2 | |
Lukas Korba | 8294415a69 | |
Lukas Korba | 4a3be9ac0b | |
Lukas Korba | 28e95efca9 | |
Lukas Korba | 702b71103b | |
Francisco Gindre | c1847d4216 | |
Lukas Korba | 59ad8f4c7b | |
Francisco Gindre | b55de57a9a | |
Francisco Gindre | 604a840517 | |
Michal Fousek | 5ce87b18a9 | |
Francisco Gindre | 69c1aa12a3 | |
Michal Fousek | f46eaf69c5 | |
Lukas Korba | 88f81e774a | |
Michal Fousek | 39d1472c45 | |
Francisco Gindre | a74dfa03ae | |
Francisco Gindre | d5b92c32c5 | |
Francisco Gindre | 72324f2a94 | |
Francisco Gindre | fe09ae7aef | |
Lukas Korba | c8037f714b | |
Lukas Korba | 37af62201d | |
Francisco Gindre | 1c1eed592d | |
Lukas Korba | f8191e33ac | |
Lukas Korba | 09380a169d | |
Francisco Gindre | bae3ec974b | |
Francisco Gindre | bb5af14f4a | |
Lukas Korba | 1d86157198 | |
Michal Fousek | 3de41fe289 | |
Michal Fousek | 3071652a65 | |
Lukas Korba | dea5b19621 | |
Michal Fousek | ff58ae718c | |
Michal Fousek | ddc6bb7d86 |
|
@ -0,0 +1,70 @@
|
|||
# Background Syncing
|
||||
|
||||
## Sources
|
||||
We encourange you to watch WWDC videos:
|
||||
- [Advances in App Background Execution]: https://developer.apple.com/videos/play/wwdc2019/707
|
||||
- [Background execution demystified]: https://developer.apple.com/videos/play/wwdc2020/10063
|
||||
|
||||
## Implementation details
|
||||
There are 4 different APIs and types of background tasks. Each one is specific and can be used for different scenarios. Synchronization of the blockchain data is time and memory consuming operation. Therefore the `BGProcessingTask` has been used. This type of task is designed to run for a longer time when certain conditions are met (watch Background execution demystified).
|
||||
|
||||
### Steps to make it work
|
||||
1. Add a capability of `background modes` in the settings of the xcode project.
|
||||
2. Turn the `Background Processing` mode on in the new capability.
|
||||
3. Add `Permitted background task scheduler identifiers` to the info.plist.
|
||||
4. Create the ID for the background task in the newly created array.
|
||||
5. Register the BGTask in `application.didFinishLaunchingWithOptions`
|
||||
```Swift
|
||||
BGTaskScheduler.shared.register(
|
||||
forTaskWithIdentifier: <ID>,
|
||||
using: DispatchQueue.main
|
||||
) { task in
|
||||
// see the next steps
|
||||
}
|
||||
```
|
||||
Note: The queue is an optional and most tutorials leave the parameter `nil` but Zashi requires main thread processing due to UI layer - therefore we pass `DispatchQueue.main`.
|
||||
6. Call a method that schedules the task execution.
|
||||
7. Start the synchronizer.
|
||||
8. Set the expiration closure and stop the synchronizer inside it
|
||||
```swift
|
||||
task.expirationHandler = {
|
||||
synchronizer.stop()
|
||||
}
|
||||
```
|
||||
9. The body of the registered task summarized:
|
||||
```swift
|
||||
BGTaskScheduler.shared.register(...) { task in
|
||||
scheduleTask() // 6
|
||||
|
||||
synchronizer.start() // 7
|
||||
|
||||
task.expirationHandler = {
|
||||
synchronizer.stop() // 8
|
||||
}
|
||||
}
|
||||
```
|
||||
10. Call `scheduleTask()` when app goes to the background so there is the initial scheduling done, the next one will be handled by the closure of the registered task. The method usually consists of:
|
||||
```Swift
|
||||
let request = BGProcessingTaskRequest(identifier: <ID>)
|
||||
|
||||
request.earliestBeginDate = <scheduledTime>
|
||||
request.requiresExternalPower = true // optional, we require the iPhone to be connected to the power
|
||||
request.requiresNetworkConnectivity = true // required
|
||||
|
||||
do {
|
||||
try BGTaskScheduler.shared.submit(request)
|
||||
} catch { // handle error }
|
||||
```
|
||||
11. Last step is to call `.setTaskCompleted(success: <bool>)` on the BGTask when the work is done. This is required by the system no matter what. We call it with `true` when the synchronizer finishes the work (up-to-date state) and with `false` for other or failed reasons (stopped state, error state, etc.).
|
||||
|
||||
You can see specific details of the Zashi implementation in:
|
||||
- Xcode project settings, steps 1-4.
|
||||
- AppDelegate.swift file, steps 5-9.
|
||||
- SecantApp.swift file, step 10.
|
||||
- RootInitialization.swift, step 11.
|
||||
|
||||
## Gotchas
|
||||
- The `requiresNetworkConnectivity` flag doesn't specify or deal with the type of connectivity. It simply allows scheduling when the iPhone is connected to the internet. We deal with it when the task is triggered. The custom check wheather the wifi is or is not connected preceeds the start of the synchronizer.
|
||||
- When the app is killed by a user in the app switcher, the scheduled BGTask is deleted. So the BGTask is triggered at the scheduled time only when the app is suspended or killed by the system. Explicit termination of the app by a user leads to termination of any background processing.
|
||||
|
||||
|
289
CHANGELOG.md
289
CHANGELOG.md
|
@ -1,4 +1,293 @@
|
|||
# Changelog
|
||||
All notable changes to this application will be documented in this file.
|
||||
|
||||
Please be aware that this changelog primarily focuses on user-related modifications, emphasizing changes that can
|
||||
directly impact users rather than highlighting other crucial architectural updates.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## 1.1.1 build 1 (2024-05-22)
|
||||
|
||||
### Added
|
||||
- Expanded transaction lists all text memos.
|
||||
- Biometric lock is used to protect Delete Zashi, Export Private Data and Send features.
|
||||
- Tapping on the error message label in the sync progress shows an alert view with the details of the error.
|
||||
- What's new screen accessible from Settings -> About.
|
||||
|
||||
### Fixed
|
||||
- Sometimes, Zashi crashed when the shield button was tapped. We fixed the crash, but shielding won't be possible due to funds being below the threshold.
|
||||
|
||||
## 1.1 build 6 (2024-05-09)
|
||||
|
||||
### Changed
|
||||
- Hide balances logic has been tweaked for better security. Shileding is not possible when balances are hidden. Send tab balances are also hidden.
|
||||
|
||||
## 1.1 build 3 (2024-05-07)
|
||||
|
||||
### Added
|
||||
- Dark mode.
|
||||
- Scan QR code from an image stored in the library.
|
||||
- Hide the balances with an eye icon on the Account or Balances tabs.
|
||||
|
||||
### Changed
|
||||
- The confirmation button at recovery phrase screen changed its name from "I got it" to "I've saved it".
|
||||
- Receive tab shows 1 QR code at a time with ability to switch between them.
|
||||
|
||||
### Fixed
|
||||
- Balances are refreshed right after the send or shielding transaction are processed.
|
||||
|
||||
## 1.0.6 build 4 (2024-04-30)
|
||||
|
||||
### Changed
|
||||
- We have added one more group of server options (zec.rocks) for increased coverage and reliability.
|
||||
- zec.rocks:443 is now default wallet option.
|
||||
|
||||
### Fixed
|
||||
- We fixed a bug issue with displaying the recovery seed phrase twice after creating a new wallet.
|
||||
|
||||
## 1.0.5 build 4 (2024-04-19)
|
||||
|
||||
### Fixed
|
||||
- Migration of DB ensures that the default Unified Address for existing wallets now contains an Orchard receiver.
|
||||
|
||||
## 1.0.5 build 2 (2024-04-17)
|
||||
|
||||
### Added
|
||||
- Open settings button added to the scan screen for a case when the camera is disabled.
|
||||
- Content of Zashi is hidden in system's app switcher.
|
||||
- Birthday field is auto-focused in the restore flow.
|
||||
- Information about restore is persisted until fully synced wallet.
|
||||
|
||||
### Changed
|
||||
- Zashi requires 1 GB of free space to operate. We have updated the user experience to display a message when this requirement is not met, indicating the actual amount of free space available. From this screen, you can access the settings to obtain the recovery phrase if needed.
|
||||
- The height of syncing label has been unified to never change the overall component's' height based on different states.
|
||||
- The input field for the recovery phrase now shows the expected format in the placeholder.
|
||||
- "No message included in transaction" has been removed from expanded transparent transaction view.
|
||||
|
||||
### Fixed
|
||||
- General clean up and bugfix.
|
||||
- Delete Zashi resets local in memory values.
|
||||
|
||||
## 1.0.4 build 2 (2024-03-29)
|
||||
|
||||
### Added
|
||||
- Tap to Copy memo.
|
||||
|
||||
### Fixed
|
||||
- Tap to Copy transaction ID button animation.
|
||||
- Transparent balance added up to the total balance.
|
||||
- Tap to transparent funds hint box area.
|
||||
|
||||
## 1.0.4 build 1 (2024-03-28)
|
||||
|
||||
### Fixed
|
||||
- Orchard subtree roots are now fetched alongside Sapling subtree roots.
|
||||
|
||||
## 1.0.3 build 1 (2024-03-27)
|
||||
|
||||
### Fixed
|
||||
- Bug in note selection when sending to a transparent recipient.
|
||||
|
||||
## 1.0.2 build 1 (2024-03-27)
|
||||
|
||||
### Fixed
|
||||
- Bug in an SQL query that prevented shielding of transparent funds.
|
||||
|
||||
## 1.0.1 build 3 (2024-03-26)
|
||||
|
||||
### Added
|
||||
- Proposal API integrated with error handling for multi-transaction Proposals.
|
||||
- Privacy info manifest.
|
||||
- Orchard support.
|
||||
- Seed validation for case when Zashi is migrated to another device.
|
||||
|
||||
### Fixed
|
||||
- White area above the keyboard has been removed.
|
||||
|
||||
## 1.0 build 3 (2024-03-13)
|
||||
|
||||
### Changed
|
||||
- Settings screen options have been reduced and some were moved to the new Advanced Settings screen.
|
||||
- Scan of QR codes has been re-worked with new design and behaviours.
|
||||
- Security warning consent extended with crash reports.
|
||||
- Available balance component shows a spinner instead of zero value when processing spendable balance.
|
||||
|
||||
### Added
|
||||
- Pending values (changes) at the Balances tab.
|
||||
- Choose a Server feature: available at settings, pre-defined servers + custom server setup.
|
||||
- Account tab UI tweaks for no transactions available.
|
||||
|
||||
### Fixed
|
||||
- Restore mode in the UI was missing when Zashi was deleted from an iPhone and reinstalled again.
|
||||
- Syncing bar in the restore mode bottom padding.
|
||||
- Missing exit button at backup phrase screen when no words are stored in the keychain.
|
||||
- Failed transactions are no longer at the top of the transaction history but mixed with the transactions around the time it failed.
|
||||
- Synchronization progress bar starts at the expected percentage as oposed to previous behaviour when it started with 0% and jumped to the expected one in a few seconds.
|
||||
- iPhone SE recovery phrase screen is not trailing words anymore.
|
||||
- Security audit issues has been resolved.
|
||||
|
||||
### Removed
|
||||
- Pull to refresh the transaction history.
|
||||
|
||||
## 0.2.0 build 15 (2024-01-31)
|
||||
|
||||
### Fixed
|
||||
- Shileding of transparent funds.
|
||||
|
||||
## 0.2.0 build 14 (2024-01-30)
|
||||
|
||||
### Updated
|
||||
- SDK 2.0.7 adopted with the performance optimizations on the rust side.
|
||||
|
||||
## 0.2.0 build 13 (2024-01-28)
|
||||
|
||||
### Added
|
||||
- Share QR code of addresses via system share dialog.
|
||||
|
||||
### Fixed
|
||||
- `Keys Missing` error dialog was sometimes triggered as a false positive due to system overload and keychain API unresponsivity in expected time. Retry logic was implemented to pass this state. Also the app always lands users to the Account tab instead of lock them on a splash screen with no options to solve this state.
|
||||
|
||||
## 0.2.0 build 12 (2024-01-20)
|
||||
|
||||
### Added
|
||||
- The exported logs also show the shielded balances (total & verified) for every finished sync metric.
|
||||
- Synchronization in the background. When the iPhone is connected to the power and wifi, the background task will try to synchronize randomly between 3-4am.
|
||||
- Restore of the wallet is now indiated in the UI throughout the application.
|
||||
- A hint box that elucidates transparent funds and shielding on the Balances tab.
|
||||
|
||||
### Fixed
|
||||
- The export buttons are disabled when exporting of the private data is in progress.
|
||||
- The alert message and title for the failed transaction send.
|
||||
|
||||
## 0.2.0 build 11 (2023-12-13)
|
||||
|
||||
### Added
|
||||
- Option to export SDK and wallet logs in `Export private data` screen.
|
||||
|
||||
### Changed
|
||||
- The background of Onboarding and some of the Settings screen has been updated to show a subtle texture of a grid pattern.
|
||||
- The sapling address + QR code has been restored on the Receive tab (for testnet only.)
|
||||
|
||||
### Fixed
|
||||
- Fixed a bug that caused spends to appear to be stuck.
|
||||
- The confirmation screen has been altered such that the message bubble is rendered only when the message is non-empty.
|
||||
|
||||
## 0.2.0 build 10 (2023-11-30)
|
||||
|
||||
### Changed
|
||||
- The way how the balances (zatoshi amounts/values) are represented has been updated accoridng to the latest requirements. In general any zatoshi value has 2 major states, expanded or abbreviated. Trailing zeroes are trimmed when expanded.
|
||||
- The `Balances` screen has been redesigned: new progress bar with the status of the synchronization, all balances available. Penging fields are disabled for now and show only zeroes until support from the SDK is implemented.
|
||||
- When the send button is tapped, the sending title + spinner is shown instead of just the spinner. Also, when the send is done, and redirect to the Account page is done, the sending transaction is already populated in the list. The lag between it was presented has been fixed.
|
||||
|
||||
### Removed
|
||||
- [testnet only] The sapling address and the QR of it has been removed from the receive screen. The only meaningful options are the UA and the transparent addresses.
|
||||
|
||||
### Added
|
||||
- Confirmation screen when sending funds. The initial screen is about filling in the address, amount and message (optional). The butoon `review` leads to a brand new screen where the summary of the transaction is presented. The send is confirmed by tapping the send button. Going back to update send data is possible via `go back` button.
|
||||
|
||||
## 0.2.0 build 9 (2023-11-14)
|
||||
|
||||
### Changed
|
||||
- Send (tab) redesigned: All the input fields are at the same screen. The screen is scrollable so it's usable on every possible iPhone.
|
||||
- Complete redesign of transactions on the Account tab. Expandable transactions show details of it, including options to copy transaction IDs as well as addresses.
|
||||
|
||||
### Added
|
||||
- The concept of read/unread transactions with the message (memo) implemented. The color of the icon of received transaction that holds message and hasn't been read yet is yellow. Once the transaction is expanded, the icon's color flips to the black and the state is persisted.
|
||||
|
||||
## 0.2.0 build 6 (2023-11-01)
|
||||
|
||||
### Added
|
||||
- Option to export private data: brand new screen accessible via Settings, where once consent acknowledged, a user can export a database of data. Important note: the data are sensitive because it holds some information about user's transactions and history but spending keys are not exported so lost of funds is not possible.
|
||||
|
||||
## 0.2.0 build 5 (2023-10-26)
|
||||
|
||||
### Changed
|
||||
- Settings screen has been redesigned and options on the screen changed.
|
||||
- Truncation of the balances changed from 8 floating points to the 3 only.
|
||||
- Restore from the seed flow and UI updated.
|
||||
|
||||
### Added
|
||||
- Option to copy the seed to the pasteboard when a new wallet is created and the seed presented.
|
||||
|
||||
## 0.2.0 build 4 (2023-10-13)
|
||||
|
||||
### Changed
|
||||
- About screen UI updated.
|
||||
- The main navigation of the Zashi changed, now the wallet is tab based with Account, Send, Receive and Balances tabs.
|
||||
- Home screen is now called Account.
|
||||
- Receive screen UI updated.
|
||||
- Recovery screen UI updated (the screen with the seed presented).
|
||||
|
||||
### Added
|
||||
- The security warning screen with that is presented when the new wallet is created now holds a link in the text that takes a user to the privacy policy.
|
||||
|
||||
## 0.2.0 build 3 (2023-10-05)
|
||||
|
||||
### Changed
|
||||
- Zashi design buttons
|
||||
- Splash screen: new animated screen with the logo + HI text.
|
||||
- Security warning screen UI updated.
|
||||
- State and progress of the synchronizer moved from the Home screen to the balance breakdown screen.
|
||||
|
||||
## 0.2.0 build 1 (2023-10-03)
|
||||
|
||||
### Changed
|
||||
- The send button is disabled until the spendable balance is not a zero.
|
||||
|
||||
### Added
|
||||
- The wallet now handles lifecycle events: when the app goes to the background and back to the foreground. That fixed lightwalletd errors.
|
||||
|
||||
# Previous Changelog records before we rethink the idea of the changelog and before Zashi design
|
||||
|
||||
## 0.0.1 build 52
|
||||
- [#709] Better error handling in tests (#713)
|
||||
|
||||
## 0.0.1 build 51
|
||||
- [#711] Transaction History not shown (#715)
|
||||
|
||||
## 0.0.1 build 50
|
||||
- [#707] Adopt latest SDK (#708)
|
||||
- [#705] Transaction detail lacks memo and addresses (#706)
|
||||
- [#265] Integrate App Rating Alert (#703)
|
||||
- [#698] RootView to use SwitchStore (#699)
|
||||
- [#691] Adopt sync/async synchronizer changes (#696)
|
||||
- [#683] Zip log files into one (#692)
|
||||
- [#684] Improvements for the derivation tool dependency (#689)
|
||||
- [#678] Adopt TCA 0.52.0 (#688)
|
||||
- [#682] Adopt removal of the Notification center on the SDK side (#687)
|
||||
|
||||
## 0.0.1 build 49
|
||||
- [#673] End to end bugfix (#679)
|
||||
Bugs fixed:
|
||||
- derivation tool live key has hardcoded mainnet so it doesn't recognise and validate zcash testnet addresses
|
||||
- send to transparent address fails because of Memo("") provided instead of nil
|
||||
- when transparent address is filled in a send form, the memo input is still present in the UI, memo is not supported by transparent addresses so it should be removed
|
||||
|
||||
## 0.0.1 build 48
|
||||
- [#676] fix About.swift not being present on mainnet target (#677)
|
||||
- [#654] Convert SDKSynchronizerDependency to regular TCA dependency (#672)
|
||||
# 0.0.1 build 47
|
||||
- [#653] Adopt SDK initialisation changes (#671)
|
||||
- [#668] Balance Breakdown design enhancements (#669)
|
||||
- [#660] Fix missing percentage on homepage while syncing (#670)
|
||||
- [#663] Shield Funds button is enabled when there are no funds to shield (#665)
|
||||
- [#666] Remove Graphics from "create new wallet" screen (#667)
|
||||
- [#661] Send Button works even if it's apparently disabled (#664)
|
||||
- [#660] Settings button is not part of a navigation bar (#662)
|
||||
- [#658] About Screen with version (#659)
|
||||
- [#652] Each logged TCA actions appears twice in the log (#657)
|
||||
|
||||
## 0.0.1 build 46
|
||||
- [#626] Small UI-UX fixes for 0.0.1-45 (#649)
|
||||
- [#650] Layout changes for the send screen (#651)
|
||||
- [#647] Adopt 0.19.1-beta (#648)
|
||||
- [#597] Sync cannot be retried after a failure (#646)
|
||||
- [#631] Make Send Form fields avoid being blocked by keyboard (#645)
|
||||
- [#599] Add ability to shield funds (#641)
|
||||
- [#632] Show error message for failed transaction (#642)
|
||||
- [#628] TAZ vs ZEC builds (#637)
|
||||
- [#639] Show valid balance after app start (#640)
|
||||
- [#618] Require specific version of SwiftGen (#638)
|
||||
# 0.0.1 build 45
|
||||
- [#635] Fix HomeTests
|
||||
- [#633] build and release from tag 0.0.1-45
|
||||
|
|
82
README.md
82
README.md
|
@ -1,40 +1,50 @@
|
|||
# secant-ios-wallet
|
||||
# Zashi iOS Wallet
|
||||
|
||||
This wallet is a Dogfooding effort towards Zcash Halo Arc / NU5 efforts.
|
||||
This is the official home of the Zashi Zcash wallet for Wallet, a no-frills
|
||||
Zcash mobile wallet leveraging the [Zcash Swift SDK](https://github.com/Electric-Coin-Company/zcash-swift-wallet-sdk).
|
||||
|
||||
# Motivation
|
||||
Dogfooding - _transitive verb_ - is the practice of an organization using its own product. This app was created to help us learn.
|
||||
# Production
|
||||
|
||||
Please take note: the wallet is not an official product by ECC, but rather a tool for learning about our libraries that it is built on. This means that we do not have robust infrastructure or user support for this application. We open sourced it as a resource to make wallet development easier for the Zcash ecosystem.
|
||||
The Zashi IOS wallet is publicly available for download in the [AppStore](https://apps.apple.com/cz/app/zashi-zcash-wallet/id1672392439).
|
||||
|
||||
# Disclaimers
|
||||
There are some known areas for improvement:
|
||||
# Zashi Discord
|
||||
|
||||
- This app is mainly intended for learning and improving the related libraries that it uses. There may be bugs.
|
||||
- Traffic analysis, like in other cryptocurrency wallets, can leak some privacy of the user.
|
||||
- The wallet requires a trust in the server to display accurate transaction information.
|
||||
Join the Zashi community on ECC Discord server, report bugs, share ideas, request new features, and help shape Zashi's journey!
|
||||
|
||||
See the [Wallet App Threat Model](https://zcash.readthedocs.io/en/latest/rtd_pages/wallet_threat_model.html)
|
||||
# Reporting an issue
|
||||
|
||||
If you'd like to report a technical issue or feature request for the IOS
|
||||
Wallet, please file a GitHub issue [here](https://github.com/Electric-Coin-Company/zashi-ios/issues/new/choose).
|
||||
|
||||
For feature requests and issues related to the Zashi user interface that are
|
||||
not iOS-specific, please file a GitHub issue [here](https://github.com/Electric-Coin-Company/zashi/issues/new/choose).
|
||||
|
||||
If you wish to report a security issue, please follow our
|
||||
[Responsible Disclosure guidelines](https://github.com/Electric-Coin-Company/zashi/blob/master/responsible_disclosure.md).
|
||||
See the [Wallet App Threat Model](https://github.com/Electric-Coin-Company/zashi/blob/master/wallet_threat_model.md)
|
||||
for more information about the security and privacy limitations of the wallet.
|
||||
|
||||
If you'd like to sign up to help us test, reach out on discord and let us know! We're always happy to get feedback!
|
||||
General Zcash questions and/or support requests may also be directed to either:
|
||||
* [Zcash Forum](https://forum.zcashcommunity.com/)
|
||||
* [Discord Community](https://discord.io/zcash-community)
|
||||
|
||||
# Description
|
||||
# Contributing
|
||||
|
||||
iOS wallet using the Zcash iOS SDK that is maintained by core developers.
|
||||
Contributions are very much welcomed! Please read our [Contributing Guidelines](/CONTRIBUTING.md)
|
||||
and [Code of Conduct](/CONDUCT.md). Our backlog has many Issues tagged with the
|
||||
`good first issue` label. Please fork the repo and make a pull request for us
|
||||
to review.
|
||||
|
||||
This a reference wallet for the following set of features:
|
||||
- z2z transactions w/ encrypted memos
|
||||
- reply-to formatted memos
|
||||
- z2t transactions
|
||||
- transparent receive-only
|
||||
- autoshielding on threshold from receive only t-address
|
||||
Zashi Wallet uses [SwiftLint](https://github.com/realm/SwiftLint) and
|
||||
[SwiftGen](https://github.com/SwiftGen/SwiftGen) to conform to our coding
|
||||
guidelines for source code and generate accessors for assets. Please install
|
||||
these locally when contributing to the project, they are run automatically when
|
||||
you build.
|
||||
|
||||
note: z means sapling shielded addresses.
|
||||
## Installation of Swiftgen & Swiftlint on Apple Silicon-based hardware
|
||||
|
||||
# Installation of Swiftgen & Swiftlint on Apple Silicon chip
|
||||
### Swiftgen
|
||||
|
||||
## Swiftgen
|
||||
Install it using homebrew
|
||||
```
|
||||
$ brew install swiftgen
|
||||
|
@ -43,26 +53,14 @@ and create a symbolic link
|
|||
```
|
||||
ln -s /opt/homebrew/bin/swiftgen /usr/local/bin
|
||||
```
|
||||
## Swiftlint
|
||||
The project is setup to work with `0.47.0` version. We recommend to install it directly using [the official 0.47.0 package](https://github.com/realm/SwiftLint/releases/download/0.47.0/SwiftLint.pkg). If you follow this step there is no symbolic link needed.
|
||||
|
||||
In case you already have swiftlint 0.47.0 ready on your machine and installed via homebrew, create a symbolic link
|
||||
### Swiftlint
|
||||
|
||||
The project is setup to work with `0.50.3` version. We recommend to install it
|
||||
directly using [the official 0.50.3 package](https://github.com/realm/SwiftLint/releases/download/0.50.3/SwiftLint.pkg).
|
||||
If you follow this step there is no symbolic link needed.
|
||||
|
||||
In case you already have swiftlint 0.50.3 ready on your machine and installed via homebrew, create a symbolic link
|
||||
```
|
||||
ln -s /opt/homebrew/bin/swiftlint /usr/local/bin
|
||||
```
|
||||
|
||||
# Contributing
|
||||
|
||||
Contributions are very much welcomed! Please read our [Contributing Guidelines](/CONTRIBUTING.md) and [Code of Conduct](/CONDUCT.md). Our backlog has many Issues tagged with the `good first issue` label. Please fork the repo and make a pull request for us to review.
|
||||
|
||||
Secant Wallet uses [SwiftLint](https://github.com/realm/SwiftLint) and [SwiftGen](https://github.com/SwiftGen/SwiftGen) to conform to our coding guidelines for source code and generate accessors for assets. Please install these locally when contributing to the project, they are run automatically when you build.
|
||||
|
||||
# Reporting an issue
|
||||
|
||||
If you wish to report a security issue, please follow our [Responsible Disclosure guidelines](https://github.com/zcash/ZcashLightClientKit/blob/master/responsible_disclosure.md).
|
||||
|
||||
For other kind of inquiries, feel welcome to open an Issue if you encounter a bug or would like to request a feature.
|
||||
|
||||
# License
|
||||
|
||||
MIT
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
||||
xcuserdata/
|
||||
DerivedData/
|
||||
.swiftpm/config/registries.json
|
||||
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
|
||||
.netrc
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AddressDetails"
|
||||
BuildableName = "AddressDetails"
|
||||
BlueprintName = "AddressDetails"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AddressDetails"
|
||||
BuildableName = "AddressDetails"
|
||||
BlueprintName = "AddressDetails"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AppVersion"
|
||||
BuildableName = "AppVersion"
|
||||
BlueprintName = "AppVersion"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AppVersion"
|
||||
BuildableName = "AppVersion"
|
||||
BlueprintName = "AppVersion"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AudioServices"
|
||||
BuildableName = "AudioServices"
|
||||
BlueprintName = "AudioServices"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AudioServices"
|
||||
BuildableName = "AudioServices"
|
||||
BlueprintName = "AudioServices"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BalanceBreakdown"
|
||||
BuildableName = "BalanceBreakdown"
|
||||
BlueprintName = "BalanceBreakdown"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "BalanceBreakdown"
|
||||
BuildableName = "BalanceBreakdown"
|
||||
BlueprintName = "BalanceBreakdown"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Home"
|
||||
BuildableName = "Home"
|
||||
BlueprintName = "Home"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Home"
|
||||
BuildableName = "Home"
|
||||
BlueprintName = "Home"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "ImportWallet"
|
||||
BuildableName = "ImportWallet"
|
||||
BlueprintName = "ImportWallet"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "ImportWallet"
|
||||
BuildableName = "ImportWallet"
|
||||
BlueprintName = "ImportWallet"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "ImportWallet"
|
||||
BuildableName = "ImportWallet"
|
||||
BlueprintName = "ImportWallet"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "ImportWallet"
|
||||
BuildableName = "ImportWallet"
|
||||
BlueprintName = "ImportWallet"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "OnboardingFlow"
|
||||
BuildableName = "OnboardingFlow"
|
||||
BlueprintName = "OnboardingFlow"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "OnboardingFlow"
|
||||
BuildableName = "OnboardingFlow"
|
||||
BlueprintName = "OnboardingFlow"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Profile"
|
||||
BuildableName = "Profile"
|
||||
BlueprintName = "Profile"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Profile"
|
||||
BuildableName = "Profile"
|
||||
BlueprintName = "Profile"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "RecoveryPhraseDisplay"
|
||||
BuildableName = "RecoveryPhraseDisplay"
|
||||
BlueprintName = "RecoveryPhraseDisplay"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "RecoveryPhraseDisplay"
|
||||
BuildableName = "RecoveryPhraseDisplay"
|
||||
BlueprintName = "RecoveryPhraseDisplay"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Scan"
|
||||
BuildableName = "Scan"
|
||||
BlueprintName = "Scan"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Scan"
|
||||
BuildableName = "Scan"
|
||||
BlueprintName = "Scan"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "SecurityWarning"
|
||||
BuildableName = "SecurityWarning"
|
||||
BlueprintName = "SecurityWarning"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "SecurityWarning"
|
||||
BuildableName = "SecurityWarning"
|
||||
BlueprintName = "SecurityWarning"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "SendFlow"
|
||||
BuildableName = "SendFlow"
|
||||
BlueprintName = "SendFlow"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "SendFlow"
|
||||
BuildableName = "SendFlow"
|
||||
BlueprintName = "SendFlow"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Settings"
|
||||
BuildableName = "Settings"
|
||||
BlueprintName = "Settings"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Settings"
|
||||
BuildableName = "Settings"
|
||||
BlueprintName = "Settings"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "TransactionList"
|
||||
BuildableName = "TransactionList"
|
||||
BlueprintName = "TransactionList"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "TransactionList"
|
||||
BuildableName = "TransactionList"
|
||||
BlueprintName = "TransactionList"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "UIComponents"
|
||||
BuildableName = "UIComponents"
|
||||
BlueprintName = "UIComponents"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "UIComponents"
|
||||
BuildableName = "UIComponents"
|
||||
BlueprintName = "UIComponents"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "UIComponents"
|
||||
BuildableName = "UIComponents"
|
||||
BlueprintName = "UIComponents"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "UIComponents"
|
||||
BuildableName = "UIComponents"
|
||||
BlueprintName = "UIComponents"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,66 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1520"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Welcome"
|
||||
BuildableName = "Welcome"
|
||||
BlueprintName = "Welcome"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Welcome"
|
||||
BuildableName = "Welcome"
|
||||
BlueprintName = "Welcome"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
|
@ -0,0 +1,383 @@
|
|||
{
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "abseil-cpp-binary",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||
"state" : {
|
||||
"revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c",
|
||||
"version" : "1.2022062300.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "app-check",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/app-check.git",
|
||||
"state" : {
|
||||
"revision" : "3e464dad87dad2d29bb29a97836789bf0f8f67d2",
|
||||
"version" : "10.18.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "combine-schedulers",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/combine-schedulers",
|
||||
"state" : {
|
||||
"revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb",
|
||||
"version" : "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "firebase-ios-sdk",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/firebase-ios-sdk",
|
||||
"state" : {
|
||||
"revision" : "f91c8167141d0279726c6f6d9d4a47c026785cbc",
|
||||
"version" : "10.21.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googleappmeasurement",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||
"state" : {
|
||||
"revision" : "cb8617fab75d181270a1d8f763f26b15c73e2e1e",
|
||||
"version" : "10.21.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googledatatransport",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||
"state" : {
|
||||
"revision" : "a732a4b47f59e4f725a2ea10f0c77e93a7131117",
|
||||
"version" : "9.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googleutilities",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||
"state" : {
|
||||
"revision" : "bc27fad73504f3d4af235de451f02ee22586ebd3",
|
||||
"version" : "7.12.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "grpc-binary",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/grpc-binary.git",
|
||||
"state" : {
|
||||
"revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98",
|
||||
"version" : "1.49.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "grpc-swift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/grpc/grpc-swift.git",
|
||||
"state" : {
|
||||
"revision" : "84bac657e9930d26e9124bac082f26586dc2d209",
|
||||
"version" : "1.19.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "gtm-session-fetcher",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||
"state" : {
|
||||
"revision" : "d415594121c9e8a4f9d79cecee0965cf35e74dbd",
|
||||
"version" : "3.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "interop-ios-for-google-sdks",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||
"state" : {
|
||||
"revision" : "2d12673670417654f08f5f90fdd62926dc3a2648",
|
||||
"version" : "100.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "leveldb",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/leveldb.git",
|
||||
"state" : {
|
||||
"revision" : "0706abcc6b0bd9cedfbb015ba840e4a780b5159b",
|
||||
"version" : "1.22.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "mnemonicswift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zcash-hackworks/MnemonicSwift",
|
||||
"state" : {
|
||||
"revision" : "716a2c32ac2bbd8a1499ac834077df42b75edc85",
|
||||
"version" : "2.2.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "nanopb",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/nanopb.git",
|
||||
"state" : {
|
||||
"revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692",
|
||||
"version" : "2.30909.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "promises",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/promises.git",
|
||||
"state" : {
|
||||
"revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e",
|
||||
"version" : "2.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "sqlite.swift",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/stephencelis/SQLite.swift.git",
|
||||
"state" : {
|
||||
"revision" : "7a2e3cd27de56f6d396e84f63beefd0267b55ccb",
|
||||
"version" : "0.14.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-atomics",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-atomics.git",
|
||||
"state" : {
|
||||
"revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10",
|
||||
"version" : "1.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-case-paths",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-case-paths",
|
||||
"state" : {
|
||||
"revision" : "551150d5e60e3be78972607d89cd69069cca3e7c",
|
||||
"version" : "1.2.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-clocks",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-clocks",
|
||||
"state" : {
|
||||
"revision" : "a8421d68068d8f45fbceb418fbf22c5dad4afd33",
|
||||
"version" : "1.0.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-collections",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-collections",
|
||||
"state" : {
|
||||
"revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2",
|
||||
"version" : "1.0.4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-composable-architecture",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-composable-architecture",
|
||||
"state" : {
|
||||
"revision" : "cf967a28a8605629559533320d604168d733fc9c",
|
||||
"version" : "1.8.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-concurrency-extras",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-concurrency-extras",
|
||||
"state" : {
|
||||
"revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71",
|
||||
"version" : "1.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-crypto",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-crypto.git",
|
||||
"state" : {
|
||||
"revision" : "60f13f60c4d093691934dc6cfdf5f508ada1f894",
|
||||
"version" : "2.6.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-custom-dump",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-custom-dump",
|
||||
"state" : {
|
||||
"revision" : "6ea3b1b6a4957806d72030a32360d4bcb155a0d2",
|
||||
"version" : "1.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-dependencies",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-dependencies",
|
||||
"state" : {
|
||||
"revision" : "09e49dd46932adfe80ce672b4b3772d79ee6c21a",
|
||||
"version" : "1.2.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-identified-collections",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-identified-collections",
|
||||
"state" : {
|
||||
"revision" : "d1e45f3e1eee2c9193f5369fa9d70a6ddad635e8",
|
||||
"version" : "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-log",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-log.git",
|
||||
"state" : {
|
||||
"revision" : "32e8d724467f8fe623624570367e3d50c5638e46",
|
||||
"version" : "1.5.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio.git",
|
||||
"state" : {
|
||||
"revision" : "635b2589494c97e48c62514bc8b37ced762e0a62",
|
||||
"version" : "2.63.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-extras",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-extras.git",
|
||||
"state" : {
|
||||
"revision" : "0e0d0aab665ff1a0659ce75ac003081f2b1c8997",
|
||||
"version" : "1.19.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-http2",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-http2.git",
|
||||
"state" : {
|
||||
"revision" : "a8ccf13fa62775277a5d56844878c828bbb3be1a",
|
||||
"version" : "1.27.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-ssl",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-ssl.git",
|
||||
"state" : {
|
||||
"revision" : "e866a626e105042a6a72a870c88b4c531ba05f83",
|
||||
"version" : "2.24.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-nio-transport-services",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-nio-transport-services.git",
|
||||
"state" : {
|
||||
"revision" : "41f4098903878418537020075a4d8a6e20a0b182",
|
||||
"version" : "1.17.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-parsing",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-parsing",
|
||||
"state" : {
|
||||
"revision" : "a0e7d73f462c1c38c59dc40a3969ac40cea42950",
|
||||
"version" : "0.13.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-perception",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-perception",
|
||||
"state" : {
|
||||
"revision" : "42240120b2a8797595433288ab4118f8042214c3",
|
||||
"version" : "1.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-protobuf",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||
"state" : {
|
||||
"revision" : "ce20dc083ee485524b802669890291c0d8090170",
|
||||
"version" : "1.22.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-syntax",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-syntax",
|
||||
"state" : {
|
||||
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
|
||||
"version" : "509.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-system",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-system.git",
|
||||
"state" : {
|
||||
"revision" : "025bcb1165deab2e20d4eaba79967ce73013f496",
|
||||
"version" : "1.2.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-url-routing",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swift-url-routing",
|
||||
"state" : {
|
||||
"revision" : "13f65cec4de950ba30f08d9bc4abcfa41f9479b9",
|
||||
"version" : "0.6.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swiftui-navigation",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/swiftui-navigation",
|
||||
"state" : {
|
||||
"revision" : "d9e72f3083c08375794afa216fb2f89c0114f303",
|
||||
"version" : "1.2.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "xctest-dynamic-overlay",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
|
||||
"state" : {
|
||||
"revision" : "b58e6627149808b40634c4552fcf2f44d0b3ca87",
|
||||
"version" : "1.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "zcash-light-client-ffi",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zcash-hackworks/zcash-light-client-ffi",
|
||||
"state" : {
|
||||
"revision" : "c90afd6cc092468e71810bc715ddb49be8210b75",
|
||||
"version" : "0.5.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "zcashlightclientkit",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/zcash/ZcashLightClientKit",
|
||||
"state" : {
|
||||
"revision" : "2ef0e00385a8495b9d7115f7d0f9f1f19f91afa8",
|
||||
"version" : "2.0.10"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 2
|
||||
}
|
|
@ -0,0 +1,795 @@
|
|||
// swift-tools-version: 5.6
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "modules",
|
||||
platforms: [
|
||||
.iOS(.v15)
|
||||
],
|
||||
products: [
|
||||
.library(name: "About", targets: ["About"]),
|
||||
.library(name: "AddressDetails", targets: ["AddressDetails"]),
|
||||
.library(name: "AppVersion", targets: ["AppVersion"]),
|
||||
.library(name: "AudioServices", targets: ["AudioServices"]),
|
||||
.library(name: "BalanceBreakdown", targets: ["BalanceBreakdown"]),
|
||||
.library(name: "BalanceFormatter", targets: ["BalanceFormatter"]),
|
||||
.library(name: "CaptureDevice", targets: ["CaptureDevice"]),
|
||||
.library(name: "CrashReporter", targets: ["CrashReporter"]),
|
||||
.library(name: "DatabaseFiles", targets: ["DatabaseFiles"]),
|
||||
.library(name: "Date", targets: ["Date"]),
|
||||
.library(name: "Deeplink", targets: ["Deeplink"]),
|
||||
.library(name: "DeleteWallet", targets: ["DeleteWallet"]),
|
||||
.library(name: "DerivationTool", targets: ["DerivationTool"]),
|
||||
.library(name: "DiskSpaceChecker", targets: ["DiskSpaceChecker"]),
|
||||
.library(name: "ExportLogs", targets: ["ExportLogs"]),
|
||||
.library(name: "FeedbackGenerator", targets: ["FeedbackGenerator"]),
|
||||
.library(name: "FileManager", targets: ["FileManager"]),
|
||||
.library(name: "Generated", targets: ["Generated"]),
|
||||
.library(name: "HideBalances", targets: ["HideBalances"]),
|
||||
.library(name: "Home", targets: ["Home"]),
|
||||
.library(name: "ImportWallet", targets: ["ImportWallet"]),
|
||||
.library(name: "LocalAuthenticationHandler", targets: ["LocalAuthenticationHandler"]),
|
||||
.library(name: "LogsHandler", targets: ["LogsHandler"]),
|
||||
.library(name: "MnemonicClient", targets: ["MnemonicClient"]),
|
||||
.library(name: "Models", targets: ["Models"]),
|
||||
.library(name: "NotEnoughFreeSpace", targets: ["NotEnoughFreeSpace"]),
|
||||
.library(name: "NumberFormatter", targets: ["NumberFormatter"]),
|
||||
.library(name: "OnboardingFlow", targets: ["OnboardingFlow"]),
|
||||
.library(name: "PartialProposalError", targets: ["PartialProposalError"]),
|
||||
.library(name: "Pasteboard", targets: ["Pasteboard"]),
|
||||
.library(name: "PrivateDataConsent", targets: ["PrivateDataConsent"]),
|
||||
.library(name: "QRImageDetector", targets: ["QRImageDetector"]),
|
||||
.library(name: "RecoveryPhraseDisplay", targets: ["RecoveryPhraseDisplay"]),
|
||||
.library(name: "ReviewRequest", targets: ["ReviewRequest"]),
|
||||
.library(name: "Root", targets: ["Root"]),
|
||||
.library(name: "Sandbox", targets: ["Sandbox"]),
|
||||
.library(name: "Scan", targets: ["Scan"]),
|
||||
.library(name: "SDKSynchronizer", targets: ["SDKSynchronizer"]),
|
||||
.library(name: "SecItem", targets: ["SecItem"]),
|
||||
.library(name: "SecurityWarning", targets: ["SecurityWarning"]),
|
||||
.library(name: "SendConfirmation", targets: ["SendConfirmation"]),
|
||||
.library(name: "SendFlow", targets: ["SendFlow"]),
|
||||
.library(name: "ServerSetup", targets: ["ServerSetup"]),
|
||||
.library(name: "Settings", targets: ["Settings"]),
|
||||
.library(name: "SupportDataGenerator", targets: ["SupportDataGenerator"]),
|
||||
.library(name: "SyncProgress", targets: ["SyncProgress"]),
|
||||
.library(name: "ReadTransactionsStorage", targets: ["ReadTransactionsStorage"]),
|
||||
.library(name: "RestoreWalletStorage", targets: ["RestoreWalletStorage"]),
|
||||
.library(name: "Tabs", targets: ["Tabs"]),
|
||||
.library(name: "TransactionList", targets: ["TransactionList"]),
|
||||
.library(name: "UIComponents", targets: ["UIComponents"]),
|
||||
.library(name: "URIParser", targets: ["URIParser"]),
|
||||
.library(name: "UserDefaults", targets: ["UserDefaults"]),
|
||||
.library(name: "UserPreferencesStorage", targets: ["UserPreferencesStorage"]),
|
||||
.library(name: "Utils", targets: ["Utils"]),
|
||||
.library(name: "WalletBalances", targets: ["WalletBalances"]),
|
||||
.library(name: "WalletConfigProvider", targets: ["WalletConfigProvider"]),
|
||||
.library(name: "WalletStorage", targets: ["WalletStorage"]),
|
||||
.library(name: "Welcome", targets: ["Welcome"]),
|
||||
.library(name: "WhatsNew", targets: ["WhatsNew"]),
|
||||
.library(name: "WhatsNewProvider", targets: ["WhatsNewProvider"]),
|
||||
.library(name: "ZcashSDKEnvironment", targets: ["ZcashSDKEnvironment"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/pointfreeco/swift-custom-dump.git", from: "1.3.0"),
|
||||
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", from: "1.9.2"),
|
||||
.package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.3.2"),
|
||||
.package(url: "https://github.com/pointfreeco/swift-url-routing", from: "0.6.0"),
|
||||
.package(url: "https://github.com/zcash-hackworks/MnemonicSwift", from: "2.2.4"),
|
||||
.package(url: "https://github.com/Electric-Coin-Company/zcash-swift-wallet-sdk", from: "2.1.6"),
|
||||
.package(url: "https://github.com/firebase/firebase-ios-sdk", from: "10.24.0")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "About",
|
||||
dependencies: [
|
||||
"AppVersion",
|
||||
"Generated",
|
||||
"RestoreWalletStorage",
|
||||
"UIComponents",
|
||||
"WhatsNew",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
],
|
||||
path: "Sources/Features/About"
|
||||
),
|
||||
.target(
|
||||
name: "AddressDetails",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"Pasteboard",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/AddressDetails"
|
||||
),
|
||||
.target(
|
||||
name: "AppVersion",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/AppVersion"
|
||||
),
|
||||
.target(
|
||||
name: "AudioServices",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/AudioServices"
|
||||
),
|
||||
.target(
|
||||
name: "BalanceBreakdown",
|
||||
dependencies: [
|
||||
"BalanceFormatter",
|
||||
"Generated",
|
||||
"DerivationTool",
|
||||
"MnemonicClient",
|
||||
"Models",
|
||||
"NumberFormatter",
|
||||
"PartialProposalError",
|
||||
"RestoreWalletStorage",
|
||||
"SDKSynchronizer",
|
||||
"SyncProgress",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletBalances",
|
||||
"WalletStorage",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/BalanceBreakdown"
|
||||
),
|
||||
.target(
|
||||
name: "BalanceFormatter",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/BalanceFormatter"
|
||||
),
|
||||
.target(
|
||||
name: "CaptureDevice",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/CaptureDevice"
|
||||
),
|
||||
.target(
|
||||
name: "CrashReporter",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "FirebaseCrashlytics", package: "firebase-ios-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/CrashReporter"
|
||||
),
|
||||
.target(
|
||||
name: "DatabaseFiles",
|
||||
dependencies: [
|
||||
"FileManager",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/DatabaseFiles"
|
||||
),
|
||||
.target(
|
||||
name: "Date",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/Date"
|
||||
),
|
||||
.target(
|
||||
name: "Deeplink",
|
||||
dependencies: [
|
||||
"DerivationTool",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "URLRouting", package: "swift-url-routing"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/Deeplink"
|
||||
),
|
||||
.target(
|
||||
name: "DeleteWallet",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"SDKSynchronizer",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/DeleteWallet"
|
||||
),
|
||||
.target(
|
||||
name: "DerivationTool",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/DerivationTool"
|
||||
),
|
||||
.target(
|
||||
name: "DiskSpaceChecker",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
],
|
||||
path: "Sources/Dependencies/DiskSpaceChecker"
|
||||
),
|
||||
.target(
|
||||
name: "ExportLogs",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"LogsHandler",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/ExportLogs"
|
||||
),
|
||||
.target(
|
||||
name: "FeedbackGenerator",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/FeedbackGenerator"
|
||||
),
|
||||
.target(
|
||||
name: "FileManager",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/FileManager"
|
||||
),
|
||||
.target(
|
||||
name: "Generated",
|
||||
resources: [.process("Resources")]
|
||||
),
|
||||
.target(
|
||||
name: "HideBalances",
|
||||
dependencies: [
|
||||
"UserDefaults",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/HideBalances"
|
||||
),
|
||||
.target(
|
||||
name: "Home",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"Models",
|
||||
"RestoreWalletStorage",
|
||||
"ReviewRequest",
|
||||
"Scan",
|
||||
"Settings",
|
||||
"SDKSynchronizer",
|
||||
"SyncProgress",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"TransactionList",
|
||||
"WalletBalances",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/Home"
|
||||
),
|
||||
.target(
|
||||
name: "ImportWallet",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"MnemonicClient",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletStorage",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/ImportWallet"
|
||||
),
|
||||
.target(
|
||||
name: "LocalAuthenticationHandler",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/LocalAuthenticationHandler"
|
||||
),
|
||||
.target(
|
||||
name: "LogsHandler",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/LogsHandler"
|
||||
),
|
||||
.target(
|
||||
name: "MnemonicClient",
|
||||
dependencies: [
|
||||
.product(name: "MnemonicSwift", package: "MnemonicSwift"),
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/MnemonicClient"
|
||||
),
|
||||
.target(
|
||||
name: "Models",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
"UIComponents",
|
||||
.product(name: "MnemonicSwift", package: "MnemonicSwift")
|
||||
],
|
||||
path: "Sources/Models"
|
||||
),
|
||||
.target(
|
||||
name: "NotEnoughFreeSpace",
|
||||
dependencies: [
|
||||
"DiskSpaceChecker",
|
||||
"Generated",
|
||||
"Settings",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/NotEnoughFreeSpace"
|
||||
),
|
||||
.target(
|
||||
name: "NumberFormatter",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/NumberFormatter"
|
||||
),
|
||||
.target(
|
||||
name: "OnboardingFlow",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"ImportWallet",
|
||||
"Models",
|
||||
"SecurityWarning",
|
||||
"UIComponents",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/OnboardingFlow"
|
||||
),
|
||||
.target(
|
||||
name: "PartialProposalError",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"SupportDataGenerator",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/PartialProposalError"
|
||||
),
|
||||
.target(
|
||||
name: "Pasteboard",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/Pasteboard"
|
||||
),
|
||||
.target(
|
||||
name: "PrivateDataConsent",
|
||||
dependencies: [
|
||||
"ExportLogs",
|
||||
"DatabaseFiles",
|
||||
"Generated",
|
||||
"Models",
|
||||
"RestoreWalletStorage",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/PrivateDataConsent"
|
||||
),
|
||||
.target(
|
||||
name: "QRImageDetector",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/QRImageDetector"
|
||||
),
|
||||
.target(
|
||||
name: "RecoveryPhraseDisplay",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"MnemonicClient",
|
||||
"Models",
|
||||
"NumberFormatter",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletStorage",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/RecoveryPhraseDisplay"
|
||||
),
|
||||
.target(
|
||||
name: "RestoreWalletStorage",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/RestoreWalletStorage"
|
||||
),
|
||||
.target(
|
||||
name: "ReviewRequest",
|
||||
dependencies: [
|
||||
"AppVersion",
|
||||
"Date",
|
||||
"UserDefaults",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/ReviewRequest"
|
||||
),
|
||||
.target(
|
||||
name: "Root",
|
||||
dependencies: [
|
||||
"CrashReporter",
|
||||
"DatabaseFiles",
|
||||
"Deeplink",
|
||||
"DerivationTool",
|
||||
"DiskSpaceChecker",
|
||||
"ExportLogs",
|
||||
"Generated",
|
||||
"HideBalances",
|
||||
"MnemonicClient",
|
||||
"Models",
|
||||
"NotEnoughFreeSpace",
|
||||
"NumberFormatter",
|
||||
"OnboardingFlow",
|
||||
"Pasteboard",
|
||||
"ReadTransactionsStorage",
|
||||
"RecoveryPhraseDisplay",
|
||||
"RestoreWalletStorage",
|
||||
"Sandbox",
|
||||
"SDKSynchronizer",
|
||||
"Tabs",
|
||||
"UIComponents",
|
||||
"UserDefaults",
|
||||
"UserPreferencesStorage",
|
||||
"Utils",
|
||||
"WalletConfigProvider",
|
||||
"WalletStorage",
|
||||
"Welcome",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/Root"
|
||||
),
|
||||
.target(
|
||||
name: "Sandbox",
|
||||
dependencies: [
|
||||
"RecoveryPhraseDisplay",
|
||||
"Scan",
|
||||
"SendFlow",
|
||||
"TransactionList",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/Sandbox"
|
||||
),
|
||||
.target(
|
||||
name: "Scan",
|
||||
dependencies: [
|
||||
"CaptureDevice",
|
||||
"Generated",
|
||||
"QRImageDetector",
|
||||
"URIParser",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/Scan"
|
||||
),
|
||||
.target(
|
||||
name: "SDKSynchronizer",
|
||||
dependencies: [
|
||||
"DatabaseFiles",
|
||||
"Models",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/SDKSynchronizer"
|
||||
),
|
||||
.target(
|
||||
name: "SecItem",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/SecItem"
|
||||
),
|
||||
.target(
|
||||
name: "SecurityWarning",
|
||||
dependencies: [
|
||||
"AppVersion",
|
||||
"Generated",
|
||||
"MnemonicClient",
|
||||
"Models",
|
||||
"NumberFormatter",
|
||||
"RecoveryPhraseDisplay",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletStorage",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/SecurityWarning"
|
||||
),
|
||||
.target(
|
||||
name: "SendConfirmation",
|
||||
dependencies: [
|
||||
"AudioServices",
|
||||
"BalanceFormatter",
|
||||
"DerivationTool",
|
||||
"Generated",
|
||||
"LocalAuthenticationHandler",
|
||||
"MnemonicClient",
|
||||
"Models",
|
||||
"PartialProposalError",
|
||||
"Scan",
|
||||
"SDKSynchronizer",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletBalances",
|
||||
"WalletStorage",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/SendConfirmation"
|
||||
),
|
||||
.target(
|
||||
name: "SendFlow",
|
||||
dependencies: [
|
||||
"AudioServices",
|
||||
"BalanceFormatter",
|
||||
"DerivationTool",
|
||||
"Generated",
|
||||
"Models",
|
||||
"Scan",
|
||||
"SDKSynchronizer",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"WalletBalances",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/SendFlow"
|
||||
),
|
||||
.target(
|
||||
name: "ServerSetup",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"SDKSynchronizer",
|
||||
"UIComponents",
|
||||
"UserPreferencesStorage",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/ServerSetup"
|
||||
),
|
||||
.target(
|
||||
name: "Settings",
|
||||
dependencies: [
|
||||
"About",
|
||||
"AppVersion",
|
||||
"DeleteWallet",
|
||||
"Generated",
|
||||
"LocalAuthenticationHandler",
|
||||
"Models",
|
||||
"Pasteboard",
|
||||
"PrivateDataConsent",
|
||||
"RecoveryPhraseDisplay",
|
||||
"RestoreWalletStorage",
|
||||
"ServerSetup",
|
||||
"SupportDataGenerator",
|
||||
"UIComponents",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/Settings"
|
||||
),
|
||||
.target(
|
||||
name: "SupportDataGenerator",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/SupportDataGenerator"
|
||||
),
|
||||
.target(
|
||||
name: "SyncProgress",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"Models",
|
||||
"SDKSynchronizer",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/SyncProgress"
|
||||
),
|
||||
.target(
|
||||
name: "ReadTransactionsStorage",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/ReadTransactionsStorage"
|
||||
),
|
||||
.target(
|
||||
name: "Tabs",
|
||||
dependencies: [
|
||||
"AddressDetails",
|
||||
"BalanceBreakdown",
|
||||
"Generated",
|
||||
"HideBalances",
|
||||
"Home",
|
||||
"RestoreWalletStorage",
|
||||
"SendConfirmation",
|
||||
"SendFlow",
|
||||
"Settings",
|
||||
"UIComponents",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/Tabs"
|
||||
),
|
||||
.target(
|
||||
name: "TransactionList",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"Models",
|
||||
"Pasteboard",
|
||||
"SDKSynchronizer",
|
||||
"ReadTransactionsStorage",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
"ZcashSDKEnvironment",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/TransactionList"
|
||||
),
|
||||
.target(
|
||||
name: "UIComponents",
|
||||
dependencies: [
|
||||
"BalanceFormatter",
|
||||
"DerivationTool",
|
||||
"Generated",
|
||||
"HideBalances",
|
||||
"NumberFormatter",
|
||||
"SupportDataGenerator",
|
||||
"Utils",
|
||||
"ZcashSDKEnvironment"
|
||||
],
|
||||
path: "Sources/UIComponents"
|
||||
),
|
||||
.target(
|
||||
name: "URIParser",
|
||||
dependencies: [
|
||||
"DerivationTool",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/URIParser"
|
||||
),
|
||||
.target(
|
||||
name: "UserDefaults",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/UserDefaults"
|
||||
),
|
||||
.target(
|
||||
name: "UserPreferencesStorage",
|
||||
dependencies: [
|
||||
"UserDefaults",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/UserPreferencesStorage"
|
||||
),
|
||||
.target(
|
||||
name: "Utils",
|
||||
dependencies: [
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk"),
|
||||
.product(name: "CasePaths", package: "swift-case-paths"),
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Utils"
|
||||
),
|
||||
.target(
|
||||
name: "WalletBalances",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"Models",
|
||||
"SDKSynchronizer",
|
||||
"UIComponents",
|
||||
"Utils",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Features/WalletBalances"
|
||||
),
|
||||
.target(
|
||||
name: "WalletConfigProvider",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
"Models",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/WalletConfigProvider"
|
||||
),
|
||||
.target(
|
||||
name: "WalletStorage",
|
||||
dependencies: [
|
||||
"Utils",
|
||||
"SecItem",
|
||||
"MnemonicClient",
|
||||
"Models",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk")
|
||||
],
|
||||
path: "Sources/Dependencies/WalletStorage"
|
||||
),
|
||||
.target(
|
||||
name: "Welcome",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"NumberFormatter",
|
||||
"UIComponents",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/Welcome"
|
||||
),
|
||||
.target(
|
||||
name: "WhatsNew",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"UIComponents",
|
||||
"WhatsNewProvider",
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Features/WhatsNew"
|
||||
),
|
||||
.target(
|
||||
name: "WhatsNewProvider",
|
||||
dependencies: [
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/WhatsNewProvider"
|
||||
),
|
||||
.target(
|
||||
name: "ZcashSDKEnvironment",
|
||||
dependencies: [
|
||||
"Generated",
|
||||
"UserDefaults",
|
||||
"UserPreferencesStorage",
|
||||
.product(name: "ZcashLightClientKit", package: "zcash-swift-wallet-sdk"),
|
||||
.product(name: "ComposableArchitecture", package: "swift-composable-architecture")
|
||||
],
|
||||
path: "Sources/Dependencies/ZcashSDKEnvironment"
|
||||
)
|
||||
]
|
||||
)
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// AppVersionInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
public var appVersion: AppVersionClient {
|
||||
get { self[AppVersionClient.self] }
|
||||
set { self[AppVersionClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct AppVersionClient {
|
||||
public let appVersion: () -> String
|
||||
public let appBuild: () -> String
|
||||
|
||||
public init(appVersion: @escaping () -> String, appBuild: @escaping () -> String) {
|
||||
self.appVersion = appVersion
|
||||
self.appBuild = appBuild
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import Foundation
|
|||
import ComposableArchitecture
|
||||
|
||||
extension AppVersionClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
public static let liveValue = Self(
|
||||
appVersion: { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "" },
|
||||
appBuild: { Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "" }
|
||||
)
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
|
||||
extension AppVersionClient {
|
||||
static let mock = Self(
|
||||
public static let mock = Self(
|
||||
appVersion: { "0.0.1" },
|
||||
appBuild: { "31" }
|
||||
)
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension AppVersionClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
appVersion: XCTUnimplemented("\(Self.self).appVersion", placeholder: ""),
|
||||
appBuild: XCTUnimplemented("\(Self.self).appBuild", placeholder: "")
|
||||
)
|
|
@ -9,12 +9,16 @@ import ComposableArchitecture
|
|||
import AVFoundation
|
||||
|
||||
extension DependencyValues {
|
||||
var audioServices: AudioServicesClient {
|
||||
public var audioServices: AudioServicesClient {
|
||||
get { self[AudioServicesClient.self] }
|
||||
set { self[AudioServicesClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct AudioServicesClient {
|
||||
let systemSoundVibrate: () -> Void
|
||||
public struct AudioServicesClient {
|
||||
public let systemSoundVibrate: () -> Void
|
||||
|
||||
public init(systemSoundVibrate: @escaping () -> Void) {
|
||||
self.systemSoundVibrate = systemSoundVibrate
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import AVFoundation
|
|||
import ComposableArchitecture
|
||||
|
||||
extension AudioServicesClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
public static let liveValue = Self(
|
||||
systemSoundVibrate: { AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate)) }
|
||||
)
|
||||
}
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension AudioServicesClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
systemSoundVibrate: XCTUnimplemented("\(Self.self).systemSoundVibrate")
|
||||
)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// BalanceFormatterInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension DependencyValues {
|
||||
public var balanceFormatter: BalanceFormatterClient {
|
||||
get { self[BalanceFormatterClient.self] }
|
||||
set { self[BalanceFormatterClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct BalanceFormatterClient {
|
||||
public var convert: (
|
||||
Zatoshi,
|
||||
ZatoshiStringRepresentation.PrefixSymbol,
|
||||
ZatoshiStringRepresentation.Format
|
||||
) -> ZatoshiStringRepresentation
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// BalanceFormatterLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension BalanceFormatterClient: DependencyKey {
|
||||
public static let liveValue = Self(
|
||||
convert: { ZatoshiStringRepresentation($0, prefixSymbol: $1, format: $2) }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// BalanceFormatterTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension BalanceFormatterClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
convert: XCTUnimplemented("\(Self.self).convert", placeholder: .placeholer)
|
||||
)
|
||||
}
|
||||
|
||||
extension BalanceFormatterClient {
|
||||
public static let noOp = Self(
|
||||
convert: { _, _, _ in .placeholer }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
//
|
||||
// ZatoshiStringRepresentation.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 10.11.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ZcashLightClientKit
|
||||
import ComposableArchitecture
|
||||
|
||||
import Generated
|
||||
import Utils
|
||||
|
||||
public struct ZatoshiStringRepresentation: Equatable {
|
||||
public enum PrefixSymbol: Equatable {
|
||||
case none
|
||||
case minus
|
||||
case plus
|
||||
}
|
||||
|
||||
public enum Format: Equatable {
|
||||
case abbreviated
|
||||
case expanded
|
||||
}
|
||||
|
||||
public let mostSignificantDigits: String
|
||||
public let leastSignificantDigits: String
|
||||
public let feeFormat = ZatoshiStringRepresentation.feeFormat
|
||||
|
||||
public init(
|
||||
_ zatoshi: Zatoshi,
|
||||
prefixSymbol: PrefixSymbol = .none,
|
||||
format: Format = .abbreviated
|
||||
) {
|
||||
var symbol = ""
|
||||
|
||||
switch prefixSymbol {
|
||||
case .minus: symbol = "-"
|
||||
case .plus: symbol = "+"
|
||||
default: break
|
||||
}
|
||||
|
||||
// 0 zatoshi case
|
||||
if zatoshi.amount == 0 {
|
||||
self.mostSignificantDigits = "\(symbol)\(Zatoshi(0).decimalZashiFormatted())"
|
||||
self.leastSignificantDigits = ""
|
||||
} else if zatoshi.amount < 100_000 && format == .abbreviated {
|
||||
// 0 for most significant but non-0 for least ones
|
||||
self.mostSignificantDigits = "\(symbol)\(Zatoshi(0).decimalZashiFormatted())..."
|
||||
self.leastSignificantDigits = ""
|
||||
} else {
|
||||
if format == .expanded {
|
||||
let formatted = zatoshi.decimalZashiFullFormatted()
|
||||
|
||||
let leastSignificantDigits = String(formatted.suffix(5))
|
||||
let mostSignificantDigits = formatted.dropLast(5)
|
||||
|
||||
var leastTrimmed = ""
|
||||
var useTheRest = false
|
||||
|
||||
for char in leastSignificantDigits.reversed() {
|
||||
if char != "0" {
|
||||
useTheRest = true
|
||||
}
|
||||
|
||||
if useTheRest {
|
||||
leastTrimmed += String(char)
|
||||
}
|
||||
}
|
||||
|
||||
leastTrimmed = String(leastTrimmed.reversed())
|
||||
|
||||
self.mostSignificantDigits = "\(symbol)\(mostSignificantDigits)"
|
||||
self.leastSignificantDigits = "\(leastTrimmed)"
|
||||
} else {
|
||||
let formatted = zatoshi.decimalZashiFormatted()
|
||||
|
||||
self.mostSignificantDigits = "\(symbol)\(formatted)"
|
||||
self.leastSignificantDigits = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ZatoshiStringRepresentation {
|
||||
static let placeholer = Self(Zatoshi(123_456_000))
|
||||
}
|
||||
|
||||
extension ZatoshiStringRepresentation {
|
||||
public static var feeFormat: String { L10n.General.fee(Zatoshi(100_000).decimalZashiFormatted()) }
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// CaptureDeviceInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
public var captureDevice: CaptureDeviceClient {
|
||||
get { self[CaptureDeviceClient.self] }
|
||||
set { self[CaptureDeviceClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct CaptureDeviceClient {
|
||||
public enum CaptureDeviceClientError: Error {
|
||||
case authorizationStatus
|
||||
case captureDevice
|
||||
case lockForConfiguration
|
||||
case torchUnavailable
|
||||
}
|
||||
|
||||
public let isAuthorized: () -> Bool
|
||||
public let isTorchAvailable: () -> Bool
|
||||
public let torch: (Bool) throws -> Void
|
||||
}
|
|
@ -9,17 +9,20 @@ import AVFoundation
|
|||
import ComposableArchitecture
|
||||
|
||||
extension CaptureDeviceClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
public static let liveValue = Self(
|
||||
isAuthorized: {
|
||||
AVCaptureDevice.authorizationStatus(for: .video) == .authorized
|
||||
},
|
||||
isTorchAvailable: {
|
||||
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else {
|
||||
throw CaptureDeviceClientError.captureDeviceFailed
|
||||
return false
|
||||
}
|
||||
|
||||
return videoCaptureDevice.hasTorch
|
||||
},
|
||||
torch: { isTorchOn in
|
||||
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else {
|
||||
throw CaptureDeviceClientError.captureDeviceFailed
|
||||
throw CaptureDeviceClientError.captureDevice
|
||||
}
|
||||
|
||||
guard videoCaptureDevice.hasTorch else {
|
||||
|
@ -31,7 +34,7 @@ extension CaptureDeviceClient: DependencyKey {
|
|||
videoCaptureDevice.torchMode = isTorchOn ? .on : .off
|
||||
videoCaptureDevice.unlockForConfiguration()
|
||||
} catch {
|
||||
throw CaptureDeviceClientError.lockFailed
|
||||
throw CaptureDeviceClientError.lockForConfiguration
|
||||
}
|
||||
}
|
||||
)
|
|
@ -9,14 +9,16 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension CaptureDeviceClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
isAuthorized: XCTUnimplemented("\(Self.self).isAuthorized", placeholder: false),
|
||||
isTorchAvailable: XCTUnimplemented("\(Self.self).isTorchAvailable", placeholder: false),
|
||||
torch: XCTUnimplemented("\(Self.self).torch")
|
||||
)
|
||||
}
|
||||
|
||||
extension CaptureDeviceClient {
|
||||
static let noOp = Self(
|
||||
public static let noOp = Self(
|
||||
isAuthorized: { false },
|
||||
isTorchAvailable: { false },
|
||||
torch: { _ in }
|
||||
)
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// CrashReportingInterface.swift
|
||||
// CrashReporterInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Francisco Gindre on 2/2/23.
|
||||
|
@ -9,24 +9,24 @@ import ComposableArchitecture
|
|||
import Foundation
|
||||
|
||||
extension DependencyValues {
|
||||
var crashReporter: CrashReporterClient {
|
||||
public var crashReporter: CrashReporterClient {
|
||||
get { self[CrashReporterClient.self] }
|
||||
set { self[CrashReporterClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct CrashReporterClient {
|
||||
public struct CrashReporterClient {
|
||||
/// Configures the crash reporter if possible.
|
||||
/// if it can't be configured this will fail silently
|
||||
var configure: (Bool) -> Void
|
||||
public var configure: (Bool) -> Void
|
||||
|
||||
/// this will test the crash reporter
|
||||
/// - Note: depending of the crash reporter this may or may not crash your app.
|
||||
var testCrash: () -> Void
|
||||
public var testCrash: () -> Void
|
||||
|
||||
/// this will tell the crash reporter that the user a has decided to opt-in crash reporting
|
||||
var optIn: () -> Void
|
||||
/// this will tell the crash reporter that the user has decided to opt-in crash reporting
|
||||
public var optIn: () -> Void
|
||||
|
||||
/// this will tell the crash reporter that the user has decided to opt-out of crash reporting
|
||||
var optOut: () -> Void
|
||||
public var optOut: () -> Void
|
||||
}
|
|
@ -6,11 +6,12 @@
|
|||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import FirebaseCore
|
||||
import Foundation
|
||||
import Firebase
|
||||
import FirebaseCrashlytics
|
||||
|
||||
extension CrashReporterClient: DependencyKey {
|
||||
static let liveValue = CrashReporterClient(
|
||||
public static let liveValue = CrashReporterClient(
|
||||
configure: { canConfigure in
|
||||
let fileName = "GoogleService-Info.plist"
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// CrashReporterTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Francisco Gindre on 2/2/23.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension CrashReporterClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
configure: XCTUnimplemented("\(Self.self).configure"),
|
||||
testCrash: XCTUnimplemented("\(Self.self).testCrash"),
|
||||
optIn: XCTUnimplemented("\(Self.self).optIn"),
|
||||
optOut: XCTUnimplemented("\(Self.self).optOut")
|
||||
)
|
||||
}
|
||||
|
||||
extension CrashReporterClient {
|
||||
public static let noOp = Self(
|
||||
configure: { _ in },
|
||||
testCrash: { },
|
||||
optIn: { },
|
||||
optOut: { }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// DatabaseFiles.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 05.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ZcashLightClientKit
|
||||
import FileManager
|
||||
|
||||
public struct DatabaseFiles {
|
||||
enum DatabaseFilesError: Error {
|
||||
case getFsBlockDbRoot
|
||||
case getDocumentsURL
|
||||
case getCacheURL
|
||||
case getDataURL
|
||||
case getOutputParamsURL
|
||||
case getPendingURL
|
||||
case getSpendParamsURL
|
||||
case nukeFiles
|
||||
case filesPresentCheck
|
||||
}
|
||||
|
||||
private let fileManager: FileManagerClient
|
||||
|
||||
public init(fileManager: FileManagerClient) {
|
||||
self.fileManager = fileManager
|
||||
}
|
||||
|
||||
func documentsDirectory() -> URL {
|
||||
do {
|
||||
return try fileManager.url(.documentDirectory, .userDomainMask, nil, true)
|
||||
} catch {
|
||||
// This is not super clean but this is second best thing when the above call fails.
|
||||
return URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Documents")
|
||||
}
|
||||
}
|
||||
|
||||
func cacheDbURL(for network: ZcashNetwork) -> URL {
|
||||
return documentsDirectory()
|
||||
.appendingPathComponent(
|
||||
"\(network.constants.defaultDbNamePrefix)cache.db",
|
||||
isDirectory: false
|
||||
)
|
||||
}
|
||||
|
||||
func dataDbURL(for network: ZcashNetwork) -> URL {
|
||||
return documentsDirectory()
|
||||
.appendingPathComponent(
|
||||
"\(network.constants.defaultDbNamePrefix)data.db",
|
||||
isDirectory: false
|
||||
)
|
||||
}
|
||||
|
||||
func outputParamsURL(for network: ZcashNetwork) -> URL {
|
||||
return documentsDirectory()
|
||||
.appendingPathComponent(
|
||||
"\(network.constants.defaultDbNamePrefix)sapling-output.params",
|
||||
isDirectory: false
|
||||
)
|
||||
}
|
||||
|
||||
func pendingDbURL(for network: ZcashNetwork) -> URL {
|
||||
return documentsDirectory()
|
||||
.appendingPathComponent(
|
||||
"\(network.constants.defaultDbNamePrefix)pending.db",
|
||||
isDirectory: false
|
||||
)
|
||||
}
|
||||
|
||||
func spendParamsURL(for network: ZcashNetwork) -> URL {
|
||||
return documentsDirectory()
|
||||
.appendingPathComponent(
|
||||
"\(network.constants.defaultDbNamePrefix)sapling-spend.params",
|
||||
isDirectory: false
|
||||
)
|
||||
}
|
||||
|
||||
func areDbFilesPresent(for network: ZcashNetwork) -> Bool {
|
||||
let dataDbURL = dataDbURL(for: network)
|
||||
return fileManager.fileExists(dataDbURL.path)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// DatabaseFilesInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension DependencyValues {
|
||||
public var databaseFiles: DatabaseFilesClient {
|
||||
get { self[DatabaseFilesClient.self] }
|
||||
set { self[DatabaseFilesClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct DatabaseFilesClient {
|
||||
public let documentsDirectory: () -> URL
|
||||
public let fsBlockDbRootFor: (ZcashNetwork) -> URL
|
||||
public let cacheDbURLFor: (ZcashNetwork) -> URL
|
||||
public var dataDbURLFor: (ZcashNetwork) -> URL
|
||||
public let outputParamsURLFor: (ZcashNetwork) -> URL
|
||||
public let pendingDbURLFor: (ZcashNetwork) -> URL
|
||||
public let spendParamsURLFor: (ZcashNetwork) -> URL
|
||||
public var areDbFilesPresentFor: (ZcashNetwork) -> Bool
|
||||
}
|
|
@ -7,40 +7,38 @@
|
|||
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
import FileManager
|
||||
|
||||
extension DatabaseFilesClient: DependencyKey {
|
||||
static let liveValue = DatabaseFilesClient.live()
|
||||
public static let liveValue = DatabaseFilesClient.live()
|
||||
|
||||
static func live(databaseFiles: DatabaseFiles = DatabaseFiles(fileManager: .live)) -> Self {
|
||||
public static func live(databaseFiles: DatabaseFiles = DatabaseFiles(fileManager: .live)) -> Self {
|
||||
Self(
|
||||
documentsDirectory: {
|
||||
try databaseFiles.documentsDirectory()
|
||||
databaseFiles.documentsDirectory()
|
||||
},
|
||||
fsBlockDbRootFor: { network in
|
||||
try databaseFiles.documentsDirectory()
|
||||
databaseFiles.documentsDirectory()
|
||||
.appendingPathComponent(network.networkType.chainName)
|
||||
.appendingPathComponent(ZcashSDK.defaultFsCacheName, isDirectory: true)
|
||||
},
|
||||
cacheDbURLFor: { network in
|
||||
try databaseFiles.cacheDbURL(for: network)
|
||||
databaseFiles.cacheDbURL(for: network)
|
||||
},
|
||||
dataDbURLFor: { network in
|
||||
try databaseFiles.dataDbURL(for: network)
|
||||
databaseFiles.dataDbURL(for: network)
|
||||
},
|
||||
outputParamsURLFor: { network in
|
||||
try databaseFiles.outputParamsURL(for: network)
|
||||
databaseFiles.outputParamsURL(for: network)
|
||||
},
|
||||
pendingDbURLFor: { network in
|
||||
try databaseFiles.pendingDbURL(for: network)
|
||||
databaseFiles.pendingDbURL(for: network)
|
||||
},
|
||||
spendParamsURLFor: { network in
|
||||
try databaseFiles.spendParamsURL(for: network)
|
||||
databaseFiles.spendParamsURL(for: network)
|
||||
},
|
||||
areDbFilesPresentFor: { network in
|
||||
try databaseFiles.areDbFilesPresent(for: network)
|
||||
},
|
||||
nukeDbFilesFor: { network in
|
||||
try databaseFiles.nukeDbFiles(for: network)
|
||||
databaseFiles.areDbFilesPresent(for: network)
|
||||
}
|
||||
)
|
||||
}
|
|
@ -8,9 +8,10 @@
|
|||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
import Utils
|
||||
|
||||
extension DatabaseFilesClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
documentsDirectory: XCTUnimplemented("\(Self.self).documentsDirectory", placeholder: .emptyURL),
|
||||
fsBlockDbRootFor: XCTUnimplemented("\(Self.self).fsBlockDbRootFor", placeholder: .emptyURL),
|
||||
cacheDbURLFor: XCTUnimplemented("\(Self.self).cacheDbURLFor", placeholder: .emptyURL),
|
||||
|
@ -18,19 +19,12 @@ extension DatabaseFilesClient: TestDependencyKey {
|
|||
outputParamsURLFor: XCTUnimplemented("\(Self.self).outputParamsURLFor", placeholder: .emptyURL),
|
||||
pendingDbURLFor: XCTUnimplemented("\(Self.self).pendingDbURLFor", placeholder: .emptyURL),
|
||||
spendParamsURLFor: XCTUnimplemented("\(Self.self).spendParamsURLFor", placeholder: .emptyURL),
|
||||
areDbFilesPresentFor: XCTUnimplemented("\(Self.self).areDbFilesPresentFor", placeholder: false),
|
||||
nukeDbFilesFor: XCTUnimplemented("\(Self.self).nukeDbFilesFor")
|
||||
areDbFilesPresentFor: XCTUnimplemented("\(Self.self).areDbFilesPresentFor", placeholder: false)
|
||||
)
|
||||
}
|
||||
|
||||
extension URL {
|
||||
/// The `DatabaseFilesClient` API returns an instance of the URL or throws an error.
|
||||
/// In order to use placeholders for the URL we need a URL instance, hence `emptyURL` and force unwrapp.
|
||||
static let emptyURL = URL(string: "http://empty.url")!// swiftlint:disable:this force_unwrapping
|
||||
}
|
||||
|
||||
extension DatabaseFilesClient {
|
||||
static let noOp = Self(
|
||||
public static let noOp = Self(
|
||||
documentsDirectory: { .emptyURL },
|
||||
fsBlockDbRootFor: { _ in .emptyURL },
|
||||
cacheDbURLFor: { _ in .emptyURL },
|
||||
|
@ -38,7 +32,6 @@ extension DatabaseFilesClient {
|
|||
outputParamsURLFor: { _ in .emptyURL },
|
||||
pendingDbURLFor: { _ in .emptyURL },
|
||||
spendParamsURLFor: { _ in .emptyURL },
|
||||
areDbFilesPresentFor: { _ in false },
|
||||
nukeDbFilesFor: { _ in }
|
||||
areDbFilesPresentFor: { _ in false }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// DateClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 04.04.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
public var date: DateClient {
|
||||
get { self[DateClient.self] }
|
||||
set { self[DateClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct DateClient {
|
||||
public let now: () -> Date
|
||||
|
||||
public init(now: @escaping () -> Date) {
|
||||
self.now = now
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// DateLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 04.04.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DateClient: DependencyKey {
|
||||
public static let liveValue = Self(
|
||||
now: { Date.now }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// DateTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension DateClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
now: XCTUnimplemented("\(Self.self).now", placeholder: Date.now)
|
||||
)
|
||||
}
|
|
@ -10,22 +10,28 @@ import URLRouting
|
|||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
struct Deeplink {
|
||||
enum Destination: Equatable {
|
||||
public struct Deeplink {
|
||||
public enum Destination: Equatable {
|
||||
case home
|
||||
case send(amount: Int64, address: String, memo: String)
|
||||
case send(amount: Int, address: String, memo: String)
|
||||
}
|
||||
|
||||
func resolveDeeplinkURL(_ url: URL, isValidZcashAddress: (String) throws -> Bool) throws -> Destination {
|
||||
public init() { }
|
||||
|
||||
public func resolveDeeplinkURL(
|
||||
_ url: URL,
|
||||
networkType: NetworkType,
|
||||
isValidZcashAddress: (String, NetworkType) throws -> Bool
|
||||
) throws -> Destination {
|
||||
// simplified format zcash:<address>
|
||||
// TODO: [#109] simplified for now until ZIP-321 is implememnted (https://github.com/zcash/secant-ios-wallet/issues/109)
|
||||
// TODO: [#109] simplified for now until ZIP-321 is implememnted (https://github.com/Electric-Coin-Company/zashi-ios/issues/109)
|
||||
let address = url.absoluteString.replacingOccurrences(of: "zcash:", with: "")
|
||||
do {
|
||||
if try isValidZcashAddress(address) {
|
||||
if try isValidZcashAddress(address, networkType) {
|
||||
return .send(amount: 0, address: address, memo: "")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// regular URL format zcash://
|
||||
let appRouter = OneOf {
|
||||
// GET /home
|
||||
|
@ -37,7 +43,7 @@ struct Deeplink {
|
|||
Route(.case(Destination.send(amount:address:memo:))) {
|
||||
Path { "home"; "send" }
|
||||
Query {
|
||||
Field("amount", default: 0) { Int64.parser() }
|
||||
Field("amount", default: 0) { Digits() }
|
||||
Field("address", .string, default: "")
|
||||
Field("memo", .string, default: "")
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// DeeplinkInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
import DerivationTool
|
||||
|
||||
extension DependencyValues {
|
||||
public var deeplink: DeeplinkClient {
|
||||
get { self[DeeplinkClient.self] }
|
||||
set { self[DeeplinkClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct DeeplinkClient {
|
||||
public let resolveDeeplinkURL: (URL, NetworkType, DerivationToolClient) throws -> Deeplink.Destination
|
||||
|
||||
public init(resolveDeeplinkURL: @escaping (URL, NetworkType, DerivationToolClient) throws -> Deeplink.Destination) {
|
||||
self.resolveDeeplinkURL = resolveDeeplinkURL
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
import ComposableArchitecture
|
||||
|
||||
extension DeeplinkClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
resolveDeeplinkURL: { try Deeplink().resolveDeeplinkURL($0, isValidZcashAddress: $1.isValidZcashAddress) }
|
||||
public static let liveValue = Self(
|
||||
resolveDeeplinkURL: { try Deeplink().resolveDeeplinkURL($0, networkType: $1, isValidZcashAddress: $2.isZcashAddress) }
|
||||
)
|
||||
}
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension DeeplinkClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
resolveDeeplinkURL: XCTUnimplemented("\(Self.self).resolveDeeplinkURL")
|
||||
)
|
||||
}
|
|
@ -9,26 +9,32 @@ import ComposableArchitecture
|
|||
import ZcashLightClientKit
|
||||
|
||||
extension DependencyValues {
|
||||
var derivationTool: DerivationToolClient {
|
||||
public var derivationTool: DerivationToolClient {
|
||||
get { self[DerivationToolClient.self] }
|
||||
set { self[DerivationToolClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct DerivationToolClient {
|
||||
public struct DerivationToolClient {
|
||||
/// Given a seed and a number of accounts, return the associated spending keys.
|
||||
/// - Parameter seed: the seed from which to derive spending keys.
|
||||
/// - Parameter accountIndex: Index of account to use. Multiple accounts are not fully
|
||||
/// supported so the default value of 0 is recommended.
|
||||
/// - Returns: the spending keys that correspond to the seed, formatted as Strings.
|
||||
var deriveSpendingKey: ([UInt8], Int) throws -> UnifiedSpendingKey
|
||||
public var deriveSpendingKey: ([UInt8], Int, NetworkType) throws -> UnifiedSpendingKey
|
||||
|
||||
/// Checks validity of the transparent address.
|
||||
var isValidTransparentAddress: (String) throws -> Bool
|
||||
/// Given a unified spending key, returns the associated unified viewwing key.
|
||||
public var deriveUnifiedFullViewingKey: (UnifiedSpendingKey, NetworkType) throws -> UnifiedFullViewingKey
|
||||
|
||||
/// Checks validity of the unified address.
|
||||
public var isUnifiedAddress: (String, NetworkType) -> Bool
|
||||
|
||||
/// Checks validity of the shielded address.
|
||||
var isValidSaplingAddress: (String) throws -> Bool
|
||||
public var isSaplingAddress: (String, NetworkType) -> Bool
|
||||
|
||||
/// Checks validity of the transparent address.
|
||||
public var isTransparentAddress: (String, NetworkType) -> Bool
|
||||
|
||||
/// Checks if given address is a valid zcash address.
|
||||
var isValidZcashAddress: (String) throws -> Bool
|
||||
public var isZcashAddress: (String, NetworkType) -> Bool
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// DerivationToolLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
|
||||
extension DerivationToolClient: DependencyKey {
|
||||
public static let liveValue = DerivationToolClient.live()
|
||||
|
||||
public static func live() -> Self {
|
||||
Self(
|
||||
deriveSpendingKey: { seed, accountIndex, networkType in
|
||||
try DerivationTool(networkType: networkType).deriveUnifiedSpendingKey(seed: seed, accountIndex: accountIndex)
|
||||
},
|
||||
deriveUnifiedFullViewingKey: { spendingKey, networkType in
|
||||
try DerivationTool(networkType: networkType).deriveUnifiedFullViewingKey(from: spendingKey)
|
||||
},
|
||||
isUnifiedAddress: { address, networkType in
|
||||
do {
|
||||
if case .unified = try Recipient(address, network: networkType) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
isSaplingAddress: { address, networkType in
|
||||
do {
|
||||
if case .sapling = try Recipient(address, network: networkType) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
isTransparentAddress: { address, networkType in
|
||||
do {
|
||||
if case .transparent = try Recipient(address, network: networkType) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
},
|
||||
isZcashAddress: { address, networkType in
|
||||
do {
|
||||
_ = try Recipient(address, network: networkType)
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// DerivationToolTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.11.2022.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
import ZcashLightClientKit
|
||||
import Utils
|
||||
|
||||
extension DerivationToolClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
deriveSpendingKey: XCTUnimplemented("\(Self.self).deriveSpendingKey"),
|
||||
deriveUnifiedFullViewingKey: XCTUnimplemented("\(Self.self).deriveUnifiedFullViewingKey"),
|
||||
isUnifiedAddress: XCTUnimplemented("\(Self.self).isUnifiedAddress", placeholder: false),
|
||||
isSaplingAddress: XCTUnimplemented("\(Self.self).isSaplingAddress", placeholder: false),
|
||||
isTransparentAddress: XCTUnimplemented("\(Self.self).isTransparentAddress", placeholder: false),
|
||||
isZcashAddress: XCTUnimplemented("\(Self.self).isZcashAddress", placeholder: false)
|
||||
)
|
||||
}
|
||||
|
||||
extension DerivationToolClient {
|
||||
public static let noOp = Self(
|
||||
deriveSpendingKey: { _, _, _ in throw "NotImplemented" },
|
||||
deriveUnifiedFullViewingKey: { _, _ in throw "NotImplemented" },
|
||||
isUnifiedAddress: { _, _ in return false },
|
||||
isSaplingAddress: { _, _ in return false },
|
||||
isTransparentAddress: { _, _ in return false },
|
||||
isZcashAddress: { _, _ in return false }
|
||||
)
|
||||
}
|
|
@ -7,17 +7,17 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
struct DiskSpaceChecker {
|
||||
public struct DiskSpaceChecker {
|
||||
/// Free space on disk in bytes required to do sync
|
||||
func freeSpaceRequiredForSync() -> Int64 {
|
||||
return 1 * 1024 * 1024 * 1024 // 1GB converted to bytes
|
||||
public func freeSpaceRequiredForSync() -> Int64 {
|
||||
1 * 1024 * 1024 * 1024 // 1GB converted to bytes
|
||||
}
|
||||
|
||||
func hasEnoughFreeSpaceForSync() -> Bool {
|
||||
return freeSpace() > freeSpaceRequiredForSync()
|
||||
public func hasEnoughFreeSpaceForSync() -> Bool {
|
||||
freeSpace() > freeSpaceRequiredForSync()
|
||||
}
|
||||
|
||||
func freeSpace() -> Int64 {
|
||||
public func freeSpace() -> Int64 {
|
||||
do {
|
||||
let fileURL = URL(fileURLWithPath: NSHomeDirectory())
|
||||
let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
|
|
@ -8,14 +8,14 @@
|
|||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var diskSpaceChecker: DiskSpaceCheckerClient {
|
||||
public var diskSpaceChecker: DiskSpaceCheckerClient {
|
||||
get { self[DiskSpaceCheckerClient.self] }
|
||||
set { self[DiskSpaceCheckerClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct DiskSpaceCheckerClient {
|
||||
var freeSpaceRequiredForSync: () -> Int64
|
||||
var hasEnoughFreeSpaceForSync: () -> Bool
|
||||
var freeSpace: () -> Int64
|
||||
public struct DiskSpaceCheckerClient {
|
||||
public var freeSpaceRequiredForSync: () -> Int64
|
||||
public var hasEnoughFreeSpaceForSync: () -> Bool
|
||||
public var freeSpace: () -> Int64
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
import ComposableArchitecture
|
||||
|
||||
extension DiskSpaceCheckerClient: DependencyKey {
|
||||
static let liveValue: Self = {
|
||||
public static let liveValue: Self = {
|
||||
let diskSpaceChecker = DiskSpaceChecker()
|
||||
return Self(
|
||||
freeSpaceRequiredForSync: { diskSpaceChecker.freeSpaceRequiredForSync() },
|
|
@ -6,13 +6,13 @@
|
|||
//
|
||||
|
||||
extension DiskSpaceCheckerClient {
|
||||
static let mockEmptyDisk = DiskSpaceCheckerClient(
|
||||
public static let mockEmptyDisk = DiskSpaceCheckerClient(
|
||||
freeSpaceRequiredForSync: { 1024 },
|
||||
hasEnoughFreeSpaceForSync: { true },
|
||||
freeSpace: { 2048 }
|
||||
)
|
||||
|
||||
static let mockFullDisk = DiskSpaceCheckerClient(
|
||||
public static let mockFullDisk = DiskSpaceCheckerClient(
|
||||
freeSpaceRequiredForSync: { 1024 },
|
||||
hasEnoughFreeSpaceForSync: { false },
|
||||
freeSpace: { 0 }
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension DiskSpaceCheckerClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
freeSpaceRequiredForSync: XCTUnimplemented("\(Self.self).freeSpaceRequiredForSync", placeholder: 0),
|
||||
hasEnoughFreeSpaceForSync: XCTUnimplemented("\(Self.self).hasEnoughFreeSpaceForSync", placeholder: false),
|
||||
freeSpace: XCTUnimplemented("\(Self.self).freeSpace", placeholder: 0)
|
|
@ -8,14 +8,14 @@
|
|||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var feedbackGenerator: FeedbackGeneratorClient {
|
||||
public var feedbackGenerator: FeedbackGeneratorClient {
|
||||
get { self[FeedbackGeneratorClient.self] }
|
||||
set { self[FeedbackGeneratorClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct FeedbackGeneratorClient {
|
||||
let generateSuccessFeedback: () -> Void
|
||||
let generateWarningFeedback: () -> Void
|
||||
let generateErrorFeedback: () -> Void
|
||||
public struct FeedbackGeneratorClient {
|
||||
public let generateSuccessFeedback: () -> Void
|
||||
public let generateWarningFeedback: () -> Void
|
||||
public let generateErrorFeedback: () -> Void
|
||||
}
|
|
@ -9,7 +9,7 @@ import UIKit
|
|||
import ComposableArchitecture
|
||||
|
||||
extension FeedbackGeneratorClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
public static let liveValue = Self(
|
||||
generateSuccessFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.success) },
|
||||
generateWarningFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.warning) },
|
||||
generateErrorFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.error) }
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension FeedbackGeneratorClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
generateSuccessFeedback: XCTUnimplemented("\(Self.self).generateSuccessFeedback"),
|
||||
generateWarningFeedback: XCTUnimplemented("\(Self.self).generateWarningFeedback"),
|
||||
generateErrorFeedback: XCTUnimplemented("\(Self.self).generateErrorFeedback")
|
||||
|
@ -17,7 +17,7 @@ extension FeedbackGeneratorClient: TestDependencyKey {
|
|||
}
|
||||
|
||||
extension FeedbackGeneratorClient {
|
||||
static let noOp = Self(
|
||||
public static let noOp = Self(
|
||||
generateSuccessFeedback: { },
|
||||
generateWarningFeedback: { },
|
||||
generateErrorFeedback: { }
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// FileManagerClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 07.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct FileManagerClient {
|
||||
public let url: (FileManager.SearchPathDirectory, FileManager.SearchPathDomainMask, URL?, Bool) throws -> URL
|
||||
public let fileExists: (String) -> Bool
|
||||
public let removeItem: (URL) throws -> Void
|
||||
|
||||
public init(
|
||||
url: @escaping (FileManager.SearchPathDirectory, FileManager.SearchPathDomainMask, URL?, Bool) throws -> URL,
|
||||
fileExists: @escaping (String) -> Bool,
|
||||
removeItem: @escaping (URL) throws -> Void)
|
||||
{
|
||||
self.url = url
|
||||
self.fileExists = fileExists
|
||||
self.removeItem = removeItem
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
extension FileManagerClient {
|
||||
static let live = FileManagerClient(
|
||||
public static let live = FileManagerClient(
|
||||
url: { searchPathDirectory, searchPathDomainMask, appropriateForURL, shouldCreate in
|
||||
try FileManager.default.url(for: searchPathDirectory, in: searchPathDomainMask, appropriateFor: appropriateForURL, create: shouldCreate)
|
||||
},
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension FileManagerClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
url: XCTUnimplemented("\(Self.self).url"),
|
||||
fileExists: XCTUnimplemented("\(Self.self).fileExists", placeholder: false),
|
||||
removeItem: XCTUnimplemented("\(Self.self).removeItem")
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// HideBalancesInterface.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import Combine
|
||||
|
||||
extension DependencyValues {
|
||||
public var hideBalances: HideBalancesClient {
|
||||
get { self[HideBalancesClient.self] }
|
||||
set { self[HideBalancesClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct HideBalancesClient {
|
||||
public enum Constants {
|
||||
static let udHideBalances = "udHideBalances"
|
||||
}
|
||||
|
||||
public var prepare: @Sendable () -> Void
|
||||
public var value: @Sendable () -> CurrentValueSubject<Bool, Never>
|
||||
public var updateValue: @Sendable (Bool) -> Void
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// HideBalancesLiveKey.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import Combine
|
||||
import UserDefaults
|
||||
|
||||
extension HideBalancesClient: DependencyKey {
|
||||
public static var liveValue: Self {
|
||||
let storage = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
return .init(
|
||||
prepare: {
|
||||
@Dependency(\.userDefaults) var userDefaults
|
||||
|
||||
if let value = userDefaults.objectForKey(Constants.udHideBalances) as? Bool {
|
||||
storage.value = value
|
||||
}
|
||||
},
|
||||
value: { storage },
|
||||
updateValue: {
|
||||
@Dependency(\.userDefaults) var userDefaults
|
||||
|
||||
userDefaults.setValue($0, Constants.udHideBalances)
|
||||
|
||||
storage.value = $0
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// HideBalancesTestKey.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
import Combine
|
||||
|
||||
extension HideBalancesClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
prepare: XCTUnimplemented("\(Self.self).prepare"),
|
||||
value: XCTUnimplemented("\(Self.self).value", placeholder: .init(false)),
|
||||
updateValue: XCTUnimplemented("\(Self.self).updateValue")
|
||||
)
|
||||
}
|
||||
|
||||
extension HideBalancesClient {
|
||||
public static let noOp = Self(
|
||||
prepare: { },
|
||||
value: { .init(false) },
|
||||
updateValue: { _ in }
|
||||
)
|
||||
}
|
|
@ -6,15 +6,14 @@
|
|||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import LocalAuthentication
|
||||
|
||||
extension DependencyValues {
|
||||
var localAuthentication: LocalAuthenticationClient {
|
||||
public var localAuthentication: LocalAuthenticationClient {
|
||||
get { self[LocalAuthenticationClient.self] }
|
||||
set { self[LocalAuthenticationClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct LocalAuthenticationClient {
|
||||
let authenticate: @Sendable () async -> Bool
|
||||
public struct LocalAuthenticationClient {
|
||||
public let authenticate: @Sendable () async -> Bool
|
||||
}
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
import ComposableArchitecture
|
||||
import LocalAuthentication
|
||||
import Generated
|
||||
|
||||
extension LocalAuthenticationClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
public static let liveValue = Self(
|
||||
authenticate: {
|
||||
let context = LAContext()
|
||||
var error: NSError?
|
|
@ -6,11 +6,11 @@
|
|||
//
|
||||
|
||||
extension LocalAuthenticationClient {
|
||||
static let mockAuthenticationSucceeded = Self(
|
||||
public static let mockAuthenticationSucceeded = Self(
|
||||
authenticate: { true }
|
||||
)
|
||||
|
||||
static let mockAuthenticationFailed = Self(
|
||||
public static let mockAuthenticationFailed = Self(
|
||||
authenticate: { false }
|
||||
)
|
||||
}
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension LocalAuthenticationClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
authenticate: XCTUnimplemented("\(Self.self).authenticate", placeholder: false)
|
||||
)
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// LogsHandlerInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 30.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
public var logsHandler: LogsHandlerClient {
|
||||
get { self[LogsHandlerClient.self] }
|
||||
set { self[LogsHandlerClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct LogsHandlerClient {
|
||||
public let exportAndStoreLogs: (String, String, String) async throws -> URL?
|
||||
|
||||
public init(exportAndStoreLogs: @escaping (String, String, String) async throws -> URL?) {
|
||||
self.exportAndStoreLogs = exportAndStoreLogs
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
//
|
||||
// LogsHandlerLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 30.01.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import OSLog
|
||||
|
||||
import Utils
|
||||
|
||||
extension LogsHandlerClient: DependencyKey {
|
||||
public static let liveValue = LogsHandlerClient(
|
||||
exportAndStoreLogs: { sdkLogs, tcaLogs, walletLogs in
|
||||
// create a directory
|
||||
let logsURL = FileManager.default.temporaryDirectory.appendingPathComponent("zashiPrivateData")
|
||||
try FileManager.default.createDirectory(atPath: logsURL.path, withIntermediateDirectories: true)
|
||||
|
||||
// export the logs
|
||||
async let sdkLogsVerbose = LogsHandlerClient.exportAndStoreLogsFor(
|
||||
key: sdkLogs,
|
||||
atURL: logsURL.appendingPathComponent("sdkLogs_verbose.txt")
|
||||
)
|
||||
async let sdkLogsSync = LogsHandlerClient.exportAndStoreLogsFor(
|
||||
key: sdkLogs,
|
||||
atURL: logsURL.appendingPathComponent("sdkLogs_sync.txt"),
|
||||
level: .info // The info level represents the sync log in the SDK
|
||||
)
|
||||
async let tcaLogs = LogsHandlerClient.exportAndStoreLogsFor(
|
||||
key: tcaLogs,
|
||||
atURL: logsURL.appendingPathComponent("tcaLogs.txt")
|
||||
)
|
||||
async let walletLogs = LogsHandlerClient.exportAndStoreLogsFor(
|
||||
key: walletLogs,
|
||||
atURL: logsURL.appendingPathComponent("walletLogs.txt")
|
||||
)
|
||||
|
||||
let logs = try await [sdkLogsVerbose, sdkLogsSync, tcaLogs, walletLogs]
|
||||
|
||||
// store the log files into the logs folder
|
||||
try logs.forEach { logsHandler in
|
||||
try logsHandler.result.write(to: logsHandler.dir, atomically: true, encoding: String.Encoding.utf8)
|
||||
}
|
||||
|
||||
// zip the logs folder
|
||||
let coordinator = NSFileCoordinator()
|
||||
var zipError: NSError?
|
||||
var archiveURL: URL?
|
||||
|
||||
archiveURL = await withCheckedContinuation { continuation in
|
||||
coordinator.coordinate(readingItemAt: logsURL, options: [.forUploading], error: &zipError) { zipURL in
|
||||
do {
|
||||
let tmpURL = try FileManager.default.url(
|
||||
for: .itemReplacementDirectory,
|
||||
in: .userDomainMask,
|
||||
appropriateFor: zipURL,
|
||||
create: true
|
||||
)
|
||||
.appendingPathComponent("zashiPrivateData.zip")
|
||||
try FileManager.default.moveItem(at: zipURL, to: tmpURL)
|
||||
continuation.resume(returning: tmpURL)
|
||||
} catch {
|
||||
continuation.resume(returning: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return archiveURL
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private extension LogsHandlerClient {
|
||||
static func exportAndStoreLogsFor(
|
||||
key: String,
|
||||
atURL: URL,
|
||||
level: OSLogEntryLog.Level = .debug
|
||||
) async throws -> (result: String, dir: URL) {
|
||||
let logsStr = try await LogStore.exportCategory(
|
||||
key,
|
||||
level: level,
|
||||
fileSize: 2_000_000 // ~ 2MB of data
|
||||
)
|
||||
|
||||
var result = ""
|
||||
logsStr?.forEach({ line in
|
||||
result.append(line)
|
||||
result.append("\n\n")
|
||||
})
|
||||
|
||||
return (result: result, dir: atURL)
|
||||
}
|
||||
}
|
|
@ -9,7 +9,13 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension LogsHandlerClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
exportAndStoreLogs: XCTUnimplemented("\(Self.self).exportAndStoreLogs")
|
||||
public static let testValue = Self(
|
||||
exportAndStoreLogs: XCTUnimplemented("\(Self.self).exportAndStoreLogs", placeholder: nil)
|
||||
)
|
||||
}
|
||||
|
||||
extension LogsHandlerClient {
|
||||
public static let noOp = Self(
|
||||
exportAndStoreLogs: { _, _, _ in nil }
|
||||
)
|
||||
}
|
|
@ -8,21 +8,21 @@
|
|||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var mnemonic: MnemonicClient {
|
||||
public var mnemonic: MnemonicClient {
|
||||
get { self[MnemonicClient.self] }
|
||||
set { self[MnemonicClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct MnemonicClient {
|
||||
public struct MnemonicClient {
|
||||
/// Random 24 words mnemonic phrase
|
||||
var randomMnemonic: () throws -> String
|
||||
public var randomMnemonic: () throws -> String
|
||||
/// Random 24 words mnemonic phrase as array of words
|
||||
var randomMnemonicWords: () throws -> [String]
|
||||
public var randomMnemonicWords: () throws -> [String]
|
||||
/// Generate deterministic seed from mnemonic phrase
|
||||
var toSeed: (String) throws -> [UInt8]
|
||||
public var toSeed: (String) throws -> [UInt8]
|
||||
/// Get this mnemonic phrase as array of words
|
||||
var asWords: (String) -> [String]
|
||||
public var asWords: (String) -> [String]
|
||||
/// Validates whether the given mnemonic is correct
|
||||
var isValid: (String) throws -> Void
|
||||
public var isValid: (String) throws -> Void
|
||||
}
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import MnemonicSwift
|
||||
|
||||
extension MnemonicClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
public static let liveValue = Self(
|
||||
randomMnemonic: {
|
||||
try Mnemonic.generateMnemonic(strength: 256)
|
||||
},
|
|
@ -8,7 +8,7 @@
|
|||
import Foundation
|
||||
|
||||
extension MnemonicClient {
|
||||
static let mock = MnemonicClient(
|
||||
public static let mock = MnemonicClient(
|
||||
randomMnemonic: {
|
||||
"""
|
||||
still champion voice habit trend flight \
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension MnemonicClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
randomMnemonic: XCTUnimplemented("\(Self.self).randomMnemonic", placeholder: ""),
|
||||
randomMnemonicWords: XCTUnimplemented("\(Self.self).randomMnemonicWords", placeholder: []),
|
||||
toSeed: XCTUnimplemented("\(Self.self).toSeed", placeholder: []),
|
||||
|
@ -19,7 +19,7 @@ extension MnemonicClient: TestDependencyKey {
|
|||
}
|
||||
|
||||
extension MnemonicClient {
|
||||
static let noOp = Self(
|
||||
public static let noOp = Self(
|
||||
randomMnemonic: { "" },
|
||||
randomMnemonicWords: { [] },
|
||||
toSeed: { _ in [] },
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// AppVersionInterface.swift
|
||||
// NumberFormatterInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 12.11.2022.
|
||||
|
@ -9,13 +9,13 @@ import Foundation
|
|||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
var numberFormatter: NumberFormatterClient {
|
||||
public var numberFormatter: NumberFormatterClient {
|
||||
get { self[NumberFormatterClient.self] }
|
||||
set { self[NumberFormatterClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct NumberFormatterClient {
|
||||
var string: (NSDecimalNumber) -> String?
|
||||
var number: (String) -> NSNumber?
|
||||
public struct NumberFormatterClient {
|
||||
public var string: (NSDecimalNumber) -> String?
|
||||
public var number: (String) -> NSNumber?
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// NumberFormatterLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 14.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import Utils
|
||||
|
||||
extension NumberFormatterClient: DependencyKey {
|
||||
public static let liveValue = NumberFormatterClient.live()
|
||||
|
||||
public static func live(numberFormatter: NumberFormatter = NumberFormatter.zcashNumberFormatter) -> Self {
|
||||
Self(
|
||||
string: { numberFormatter.string(from: $0) },
|
||||
number: { numberFormatter.number(from: $0) }
|
||||
)
|
||||
}
|
||||
}
|
|
@ -9,14 +9,14 @@ import ComposableArchitecture
|
|||
import XCTestDynamicOverlay
|
||||
|
||||
extension NumberFormatterClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
string: XCTUnimplemented("\(Self.self).string", placeholder: nil),
|
||||
number: XCTUnimplemented("\(Self.self).number", placeholder: nil)
|
||||
)
|
||||
}
|
||||
|
||||
extension NumberFormatterClient {
|
||||
static let noOp = Self(
|
||||
public static let noOp = Self(
|
||||
string: { _ in nil },
|
||||
number: { _ in nil }
|
||||
)
|
|
@ -6,15 +6,16 @@
|
|||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import Utils
|
||||
|
||||
extension DependencyValues {
|
||||
var pasteboard: PasteboardClient {
|
||||
public var pasteboard: PasteboardClient {
|
||||
get { self[PasteboardClient.self] }
|
||||
set { self[PasteboardClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
struct PasteboardClient {
|
||||
let setString: (RedactableString) -> Void
|
||||
let getString: () -> RedactableString?
|
||||
public struct PasteboardClient {
|
||||
public let setString: (RedactableString) -> Void
|
||||
public let getString: () -> RedactableString?
|
||||
}
|
|
@ -9,7 +9,7 @@ import ComposableArchitecture
|
|||
import UIKit
|
||||
|
||||
extension PasteboardClient: DependencyKey {
|
||||
static let liveValue = Self(
|
||||
public static let liveValue = Self(
|
||||
setString: { UIPasteboard.general.string = $0.data },
|
||||
getString: { UIPasteboard.general.string?.redacted }
|
||||
)
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
import Utils
|
||||
|
||||
extension PasteboardClient: TestDependencyKey {
|
||||
static let testValue = Self(
|
||||
public static let testValue = Self(
|
||||
setString: XCTUnimplemented("\(Self.self).setString"),
|
||||
getString: XCTUnimplemented("\(Self.self).getString", placeholder: "".redacted)
|
||||
)
|
||||
|
@ -19,7 +20,7 @@ extension PasteboardClient: TestDependencyKey {
|
|||
var string: String?
|
||||
}
|
||||
|
||||
static let testPasteboard = Self(
|
||||
public static let testPasteboard = Self(
|
||||
setString: { TestPasteboard.general.string = $0.data },
|
||||
getString: { TestPasteboard.general.string?.redacted }
|
||||
)
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// QRImageDetectorInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 2024-04-18.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
public var qrImageDetector: QRImageDetectorClient {
|
||||
get { self[QRImageDetectorClient.self] }
|
||||
set { self[QRImageDetectorClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct QRImageDetectorClient {
|
||||
public var check: @Sendable (UIImage?) -> [String]?
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// QRImageDetectorLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 2024-04-18.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import CoreImage
|
||||
|
||||
extension QRImageDetectorClient: DependencyKey {
|
||||
public static let liveValue = Self(
|
||||
check: { image in
|
||||
guard let image else { return nil }
|
||||
guard let ciImage = CIImage(image: image) else { return nil }
|
||||
|
||||
let detectorOptions = [CIDetectorAccuracy: CIDetectorAccuracyHigh]
|
||||
let qrDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: CIContext(), options: detectorOptions)
|
||||
let decoderOptions = [CIDetectorImageOrientation: ciImage.properties[(kCGImagePropertyOrientation as String)] ?? 1]
|
||||
let features = qrDetector?.features(in: ciImage, options: decoderOptions)
|
||||
|
||||
return features?.compactMap {
|
||||
($0 as? CIQRCodeFeature)?.messageString
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//
|
||||
// QRImageDetectorTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 2024-04-18.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension QRImageDetectorClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
check: XCTUnimplemented("\(Self.self).check", placeholder: nil)
|
||||
)
|
||||
}
|
||||
|
||||
extension QRImageDetectorClient {
|
||||
public static let noOp = Self(
|
||||
check: { _ in nil }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// ReadTransactionsStorageInterface.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import Utils
|
||||
|
||||
extension DependencyValues {
|
||||
public var readTransactionsStorage: ReadTransactionsStorageClient {
|
||||
get { self[ReadTransactionsStorageClient.self] }
|
||||
set { self[ReadTransactionsStorageClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReadTransactionsStorageClient {
|
||||
public enum Constants {
|
||||
static let entityName = "ReadTransactionsStorageEntity"
|
||||
static let modelName = "ReadTransactionsStorageModel"
|
||||
static let availabilityEntityName = "ReadTransactionsStorageAvailabilityTimestampEntity"
|
||||
}
|
||||
|
||||
public enum ReadTransactionsStorageError: Error {
|
||||
case createEntity
|
||||
case availability
|
||||
}
|
||||
|
||||
public let markIdAsRead: (RedactableString) throws -> Void
|
||||
public var readIds: () throws -> [RedactableString: Bool]
|
||||
public var availabilityTimestamp: () throws -> TimeInterval
|
||||
public var nukeWallet: () throws -> Void
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
//
|
||||
// ReadTransactionsStorageLiveKey.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import CoreData
|
||||
import Utils
|
||||
|
||||
extension ReadTransactionsStorageClient: DependencyKey {
|
||||
public static let liveValue = Self(
|
||||
markIdAsRead: {
|
||||
let context = persistentContainer.viewContext
|
||||
|
||||
if let entity = NSEntityDescription.entity(
|
||||
forEntityName: ReadTransactionsStorageClient.Constants.entityName,
|
||||
in: context
|
||||
) {
|
||||
let newRead = NSManagedObject(entity: entity, insertInto: context)
|
||||
|
||||
newRead.setValue($0.data, forKey: "id")
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
} else {
|
||||
throw ReadTransactionsStorageError.createEntity
|
||||
}
|
||||
},
|
||||
readIds: {
|
||||
let context = persistentContainer.viewContext
|
||||
|
||||
let request = NSFetchRequest<NSFetchRequestResult>(entityName: ReadTransactionsStorageClient.Constants.entityName)
|
||||
request.returnsObjectsAsFaults = false
|
||||
|
||||
do {
|
||||
let result = try context.fetch(request)
|
||||
|
||||
if let managedObjects = result as? [NSManagedObject] {
|
||||
let ids = managedObjects.compactMap { element in
|
||||
(element.value(forKey: "id") as? String)?.redacted
|
||||
}
|
||||
|
||||
var idsDict: [RedactableString: Bool] = [:]
|
||||
|
||||
ids.forEach { id in
|
||||
idsDict[id] = true
|
||||
}
|
||||
|
||||
return idsDict
|
||||
}
|
||||
|
||||
return [:]
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
},
|
||||
availabilityTimestamp: {
|
||||
let context = persistentContainer.viewContext
|
||||
|
||||
// check presence of the timestamp
|
||||
let request = NSFetchRequest<NSFetchRequestResult>(entityName: ReadTransactionsStorageClient.Constants.availabilityEntityName)
|
||||
request.returnsObjectsAsFaults = false
|
||||
|
||||
do {
|
||||
let result = try context.fetch(request)
|
||||
|
||||
if let managedObjects = result as? [NSManagedObject] {
|
||||
// no timestamp stored, create one
|
||||
if managedObjects.isEmpty {
|
||||
if let entity = NSEntityDescription.entity(
|
||||
forEntityName: ReadTransactionsStorageClient.Constants.availabilityEntityName,
|
||||
in: context
|
||||
) {
|
||||
let newAvailability = NSManagedObject(entity: entity, insertInto: context)
|
||||
let now = Date.now.timeIntervalSince1970
|
||||
|
||||
newAvailability.setValue(now, forKey: "timestamp")
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
|
||||
return now
|
||||
} else {
|
||||
throw ReadTransactionsStorageError.createEntity
|
||||
}
|
||||
} else {
|
||||
if let timestamp = managedObjects.first?.value(forKey: "timestamp") as? TimeInterval {
|
||||
return timestamp
|
||||
}
|
||||
|
||||
throw ReadTransactionsStorageError.availability
|
||||
}
|
||||
} else {
|
||||
throw ReadTransactionsStorageError.availability
|
||||
}
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
},
|
||||
nukeWallet: {
|
||||
let context = persistentContainer.viewContext
|
||||
|
||||
let deleteRequestIds = NSBatchDeleteRequest(
|
||||
fetchRequest: NSFetchRequest<NSFetchRequestResult>(
|
||||
entityName: ReadTransactionsStorageClient.Constants.entityName
|
||||
)
|
||||
)
|
||||
let deleteRequestTimestamp = NSBatchDeleteRequest(
|
||||
fetchRequest: NSFetchRequest<NSFetchRequestResult>(
|
||||
entityName: ReadTransactionsStorageClient.Constants.availabilityEntityName
|
||||
)
|
||||
)
|
||||
|
||||
do {
|
||||
try context.execute(deleteRequestIds)
|
||||
try context.execute(deleteRequestTimestamp)
|
||||
try context.save()
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private extension ReadTransactionsStorageClient {
|
||||
static let persistentContainer: NSPersistentContainer = {
|
||||
let container = NSPersistentContainer(name: ReadTransactionsStorageClient.Constants.modelName)
|
||||
|
||||
container.loadPersistentStores { description, error in
|
||||
if let error = error {
|
||||
fatalError("Unable to load persistent stores: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
return container
|
||||
}()
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// ReadTransactionsStorageTestKey.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 11.11.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension ReadTransactionsStorageClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
markIdAsRead: XCTUnimplemented("\(Self.self).markIdAsRead"),
|
||||
readIds: XCTUnimplemented("\(Self.self).readIds", placeholder: [:]),
|
||||
availabilityTimestamp: XCTUnimplemented("\(Self.self).availabilityTimestamp", placeholder: 0),
|
||||
nukeWallet: XCTUnimplemented("\(Self.self).nukeWallet")
|
||||
)
|
||||
}
|
||||
|
||||
extension ReadTransactionsStorageClient {
|
||||
public static let noOp = Self(
|
||||
markIdAsRead: { _ in },
|
||||
readIds: { [:] },
|
||||
availabilityTimestamp: { 0 },
|
||||
nukeWallet: { }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// RestoreWalletStorageInterface.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 19.12.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import Combine
|
||||
|
||||
extension DependencyValues {
|
||||
public var restoreWalletStorage: RestoreWalletStorageClient {
|
||||
get { self[RestoreWalletStorageClient.self] }
|
||||
set { self[RestoreWalletStorageClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct RestoreWalletStorageClient {
|
||||
public var value: @Sendable () async -> AsyncStream<Bool>
|
||||
public var updateValue: @Sendable (Bool) async -> Void
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// RestoreWalletStorageLiveKey.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 19.12.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import Combine
|
||||
|
||||
extension RestoreWalletStorageClient: DependencyKey {
|
||||
public static var liveValue: Self {
|
||||
let storage = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
return .init(
|
||||
value: {
|
||||
AsyncStream { continuation in
|
||||
let cancellable = storage.sink {
|
||||
continuation.yield($0)
|
||||
}
|
||||
|
||||
continuation.onTermination = { _ in
|
||||
cancellable.cancel()
|
||||
}
|
||||
}
|
||||
},
|
||||
updateValue: { storage.value = $0 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension AsyncStream<Bool> {
|
||||
static let placeholder = AsyncStream { continuation in continuation.finish() }
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// RestoreWalletStorageTestKey.swift
|
||||
//
|
||||
//
|
||||
// Created by Lukáš Korba on 19.12.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
import Combine
|
||||
|
||||
extension RestoreWalletStorageClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
value: XCTUnimplemented("\(Self.self).value", placeholder: .placeholder),
|
||||
updateValue: XCTUnimplemented("\(Self.self).updateValue")
|
||||
)
|
||||
}
|
||||
|
||||
extension RestoreWalletStorageClient {
|
||||
public static let noOp = Self(
|
||||
value: { .placeholder },
|
||||
updateValue: { _ in }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// ReviewRequestInterface.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 3.4.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension DependencyValues {
|
||||
public var reviewRequest: ReviewRequestClient {
|
||||
get { self[ReviewRequestClient.self] }
|
||||
set { self[ReviewRequestClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct ReviewRequestClient {
|
||||
public let canRequestReview: () -> Bool
|
||||
public let foundTransactions: () -> Void
|
||||
public let reviewRequested: () -> Void
|
||||
public let syncFinished: () -> Void
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// ReviewRequestLiveKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 3.4.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
import AppVersion
|
||||
import Date
|
||||
import UserDefaults
|
||||
|
||||
extension ReviewRequestClient: DependencyKey {
|
||||
public static let liveValue = ReviewRequestClient.live()
|
||||
|
||||
public static func live(
|
||||
appVersion: AppVersionClient = .liveValue,
|
||||
date: DateClient = .liveValue,
|
||||
userDefaults: UserDefaultsClient = .live()
|
||||
) -> Self {
|
||||
Self(
|
||||
canRequestReview: {
|
||||
// set of conditions that must be fulfilled in order to trigger review request
|
||||
|
||||
// the wallet must be synced
|
||||
guard userDefaults.objectForKey(Constants.latestSyncKey) != nil else { return false }
|
||||
|
||||
// the version is ether nil or latest review is from some older version
|
||||
let currentVersion = appVersion.appVersion()
|
||||
if let storedVersion = userDefaults.objectForKey(Constants.versionKey) as? String {
|
||||
guard currentVersion.compare(storedVersion, options: .numeric) == .orderedDescending else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// there has been at least one found transaction since the very first sync
|
||||
guard userDefaults.objectForKey(Constants.foundTransactionsKey) != nil else { return false }
|
||||
|
||||
return true
|
||||
},
|
||||
foundTransactions: {
|
||||
// only if there's the very first sync stored
|
||||
guard userDefaults.objectForKey(Constants.latestSyncKey) != nil else { return }
|
||||
userDefaults.setValue(date.now().timeIntervalSince1970, Constants.foundTransactionsKey)
|
||||
},
|
||||
reviewRequested: {
|
||||
// the review has been requested, update the version and timestamp
|
||||
userDefaults.setValue(date.now().timeIntervalSince1970, Constants.reviewRequestedKey)
|
||||
userDefaults.setValue(appVersion.appVersion(), Constants.versionKey)
|
||||
},
|
||||
syncFinished: {
|
||||
// synchronizer's sync has been finished successfuly
|
||||
userDefaults.setValue(date.now().timeIntervalSince1970, Constants.latestSyncKey)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
extension ReviewRequestClient {
|
||||
public enum Constants: CaseIterable {
|
||||
public static let foundTransactionsKey = "ReviewRequestClient.foundTransactions"
|
||||
public static let latestSyncKey = "ReviewRequestClient.latestSyncKey"
|
||||
public static let reviewRequestedKey = "ReviewRequestClient.reviewRequestedKey"
|
||||
public static let versionKey = "ReviewRequestClient.versionKey"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// ReviewRequestTestKey.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 3.4.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
import XCTestDynamicOverlay
|
||||
|
||||
extension ReviewRequestClient: TestDependencyKey {
|
||||
public static let testValue = Self(
|
||||
canRequestReview: XCTUnimplemented("\(Self.self).canRequestReview", placeholder: false),
|
||||
foundTransactions: XCTUnimplemented("\(Self.self).foundTransactions"),
|
||||
reviewRequested: XCTUnimplemented("\(Self.self).reviewRequested"),
|
||||
syncFinished: XCTUnimplemented("\(Self.self).syncFinished")
|
||||
)
|
||||
}
|
||||
|
||||
extension ReviewRequestClient {
|
||||
public static let noOp = Self(
|
||||
canRequestReview: { false },
|
||||
foundTransactions: { },
|
||||
reviewRequested: { },
|
||||
syncFinished: { }
|
||||
)
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// SDKSynchronizerClient.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 13.04.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
import Models
|
||||
|
||||
extension DependencyValues {
|
||||
public var sdkSynchronizer: SDKSynchronizerClient {
|
||||
get { self[SDKSynchronizerClient.self] }
|
||||
set { self[SDKSynchronizerClient.self] = newValue }
|
||||
}
|
||||
}
|
||||
|
||||
public struct SDKSynchronizerClient {
|
||||
public enum CreateProposedTransactionsResult: Equatable {
|
||||
case failure
|
||||
case partial(txIds: [String], statuses: [String])
|
||||
case success
|
||||
}
|
||||
|
||||
public let stateStream: () -> AnyPublisher<SynchronizerState, Never>
|
||||
public let eventStream: () -> AnyPublisher<SynchronizerEvent, Never>
|
||||
public let latestState: () -> SynchronizerState
|
||||
|
||||
public let prepareWith: ([UInt8], BlockHeight, WalletInitMode) async throws -> Void
|
||||
public let start: (_ retry: Bool) async throws -> Void
|
||||
public let stop: () -> Void
|
||||
public let isSyncing: () -> Bool
|
||||
public let isInitialized: () -> Bool
|
||||
|
||||
public let rewind: (RewindPolicy) -> AnyPublisher<Void, Error>
|
||||
|
||||
public var getAllTransactions: () async throws -> [TransactionState]
|
||||
|
||||
public let getUnifiedAddress: (_ account: Int) async throws -> UnifiedAddress?
|
||||
public let getTransparentAddress: (_ account: Int) async throws -> TransparentAddress?
|
||||
public let getSaplingAddress: (_ accountIndex: Int) async throws -> SaplingAddress?
|
||||
|
||||
public let getAccountBalance: (_ accountIndex: Int) async throws -> AccountBalance?
|
||||
|
||||
public var sendTransaction: (UnifiedSpendingKey, Zatoshi, Recipient, Memo?) async throws -> TransactionState
|
||||
public let shieldFunds: (UnifiedSpendingKey, Memo, Zatoshi) async throws -> TransactionState
|
||||
|
||||
public var wipe: () -> AnyPublisher<Void, Error>?
|
||||
|
||||
public var switchToEndpoint: (LightWalletEndpoint) async throws -> Void
|
||||
|
||||
// Proposals
|
||||
public var proposeTransfer: (Int, Recipient, Zatoshi, Memo?) async throws -> Proposal
|
||||
public var createProposedTransactions: (Proposal, UnifiedSpendingKey) async throws -> CreateProposedTransactionsResult
|
||||
public var proposeShielding: (Int, Zatoshi, Memo, TransparentAddress?) async throws -> Proposal?
|
||||
|
||||
public var isSeedRelevantToAnyDerivedAccount: ([UInt8]) async throws -> Bool
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
//
|
||||
// SDKSynchronizerLive.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 15.11.2022.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import ComposableArchitecture
|
||||
import ZcashLightClientKit
|
||||
import DatabaseFiles
|
||||
import Models
|
||||
import ZcashSDKEnvironment
|
||||
|
||||
extension SDKSynchronizerClient: DependencyKey {
|
||||
public static let liveValue: SDKSynchronizerClient = Self.live()
|
||||
|
||||
public static func live(
|
||||
databaseFiles: DatabaseFilesClient = .liveValue
|
||||
) -> Self {
|
||||
@Dependency (\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||
|
||||
let network = zcashSDKEnvironment.network
|
||||
|
||||
#if DEBUG
|
||||
let loggingPolicy = Initializer.LoggingPolicy.default(.debug)
|
||||
#else
|
||||
let loggingPolicy = Initializer.LoggingPolicy.noLogging
|
||||
#endif
|
||||
|
||||
let initializer = Initializer(
|
||||
cacheDbURL: databaseFiles.cacheDbURLFor(network),
|
||||
fsBlockDbRoot: databaseFiles.fsBlockDbRootFor(network),
|
||||
generalStorageURL: databaseFiles.documentsDirectory(),
|
||||
dataDbURL: databaseFiles.dataDbURLFor(network),
|
||||
endpoint: zcashSDKEnvironment.endpoint(),
|
||||
network: network,
|
||||
spendParamsURL: databaseFiles.spendParamsURLFor(network),
|
||||
outputParamsURL: databaseFiles.outputParamsURLFor(network),
|
||||
saplingParamsSourceURL: SaplingParamsSourceURL.default,
|
||||
loggingPolicy: loggingPolicy
|
||||
)
|
||||
|
||||
let synchronizer = SDKSynchronizer(initializer: initializer)
|
||||
|
||||
return SDKSynchronizerClient(
|
||||
stateStream: { synchronizer.stateStream },
|
||||
eventStream: { synchronizer.eventStream },
|
||||
latestState: { synchronizer.latestState },
|
||||
prepareWith: { seedBytes, walletBirtday, walletMode in
|
||||
let result = try await synchronizer.prepare(with: seedBytes, walletBirthday: walletBirtday, for: walletMode)
|
||||
if result != .success { throw ZcashError.synchronizerNotPrepared }
|
||||
},
|
||||
start: { retry in try await synchronizer.start(retry: retry) },
|
||||
stop: { synchronizer.stop() },
|
||||
isSyncing: { synchronizer.latestState.syncStatus.isSyncing },
|
||||
isInitialized: { synchronizer.latestState.syncStatus != SyncStatus.unprepared },
|
||||
rewind: { synchronizer.rewind($0) },
|
||||
getAllTransactions: {
|
||||
let clearedTransactions = try await synchronizer.allTransactions()
|
||||
|
||||
var clearedTxs: [TransactionState] = []
|
||||
|
||||
for clearedTransaction in clearedTransactions {
|
||||
var transaction = TransactionState.init(
|
||||
transaction: clearedTransaction,
|
||||
memos: clearedTransaction.memoCount > 0 ? try await synchronizer.getMemos(for: clearedTransaction) : nil,
|
||||
latestBlockHeight: try await SDKSynchronizerClient.latestBlockHeight(synchronizer: synchronizer)
|
||||
)
|
||||
|
||||
let recipients = await synchronizer.getRecipients(for: clearedTransaction)
|
||||
let addresses = recipients.compactMap {
|
||||
if case let .address(address) = $0 {
|
||||
return address
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
transaction.zAddress = addresses.first?.stringEncoded
|
||||
if let someAddress = addresses.first, case .transparent = someAddress {
|
||||
transaction.isTransparentRecipient = true
|
||||
}
|
||||
|
||||
clearedTxs.append(transaction)
|
||||
}
|
||||
|
||||
return clearedTxs
|
||||
},
|
||||
getUnifiedAddress: { try await synchronizer.getUnifiedAddress(accountIndex: $0) },
|
||||
getTransparentAddress: { try await synchronizer.getTransparentAddress(accountIndex: $0) },
|
||||
getSaplingAddress: { try await synchronizer.getSaplingAddress(accountIndex: $0) },
|
||||
getAccountBalance: { try await synchronizer.getAccountBalance(accountIndex: $0) },
|
||||
sendTransaction: { spendingKey, amount, recipient, memo in
|
||||
let pendingTransaction = try await synchronizer.sendToAddress(
|
||||
spendingKey: spendingKey,
|
||||
zatoshi: amount,
|
||||
toAddress: recipient,
|
||||
memo: memo
|
||||
)
|
||||
|
||||
return TransactionState(
|
||||
transaction: pendingTransaction,
|
||||
latestBlockHeight: try await SDKSynchronizerClient.latestBlockHeight(synchronizer: synchronizer)
|
||||
)
|
||||
},
|
||||
shieldFunds: { spendingKey, memo, shieldingThreshold in
|
||||
let pendingTransaction = try await synchronizer.shieldFunds(
|
||||
spendingKey: spendingKey,
|
||||
memo: memo,
|
||||
shieldingThreshold: shieldingThreshold
|
||||
)
|
||||
|
||||
return TransactionState(
|
||||
transaction: pendingTransaction,
|
||||
latestBlockHeight: try await SDKSynchronizerClient.latestBlockHeight(synchronizer: synchronizer)
|
||||
)
|
||||
},
|
||||
wipe: { synchronizer.wipe() },
|
||||
switchToEndpoint: { endpoint in
|
||||
try await synchronizer.switchTo(endpoint: endpoint)
|
||||
},
|
||||
proposeTransfer: { accountIndex, recipient, amount, memo in
|
||||
try await synchronizer.proposeTransfer(
|
||||
accountIndex: accountIndex,
|
||||
recipient: recipient,
|
||||
amount: amount,
|
||||
memo: memo
|
||||
)
|
||||
},
|
||||
createProposedTransactions: { proposal, spendingKey in
|
||||
let stream = try await synchronizer.createProposedTransactions(
|
||||
proposal: proposal,
|
||||
spendingKey: spendingKey
|
||||
)
|
||||
|
||||
let transactionCount = proposal.transactionCount()
|
||||
var successCount = 0
|
||||
var iterator = stream.makeAsyncIterator()
|
||||
|
||||
var txIds: [String] = []
|
||||
var statuses: [String] = []
|
||||
|
||||
for _ in 1...transactionCount {
|
||||
if let transactionSubmitResult = try await iterator.next() {
|
||||
switch transactionSubmitResult {
|
||||
case .success(txId: let id):
|
||||
successCount += 1
|
||||
txIds.append(id.toHexStringTxId())
|
||||
statuses.append("success")
|
||||
case let .grpcFailure(txId: id, error: error):
|
||||
txIds.append(id.toHexStringTxId())
|
||||
statuses.append(error.localizedDescription)
|
||||
case let .submitFailure(txId: id, code: code, description: description):
|
||||
txIds.append(id.toHexStringTxId())
|
||||
statuses.append("code: \(code) desc: \(description)")
|
||||
case .notAttempted(txId: let id):
|
||||
txIds.append(id.toHexStringTxId())
|
||||
statuses.append("notAttempted")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if successCount == 0 {
|
||||
return .failure
|
||||
} else if successCount == transactionCount {
|
||||
return .success
|
||||
} else {
|
||||
return .partial(txIds: txIds, statuses: statuses)
|
||||
}
|
||||
},
|
||||
proposeShielding: { accountIndex, shieldingThreshold, memo, transparentReceiver in
|
||||
try await synchronizer.proposeShielding(
|
||||
accountIndex: accountIndex,
|
||||
shieldingThreshold: shieldingThreshold,
|
||||
memo: memo,
|
||||
transparentReceiver: transparentReceiver
|
||||
)
|
||||
},
|
||||
isSeedRelevantToAnyDerivedAccount: { seed in
|
||||
try await synchronizer.isSeedRelevantToAnyDerivedAccount(seed: seed)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [#1313] SDK improvements so a client doesn't need to determing if the transaction isPending
|
||||
// https://github.com/zcash/ZcashLightClientKit/issues/1313
|
||||
// Once #1313 is done, cleint will no longer need to call for a `latestHeight()`
|
||||
private extension SDKSynchronizerClient {
|
||||
static func latestBlockHeight(synchronizer: SDKSynchronizer) async throws -> BlockHeight {
|
||||
let latestBlockHeight: BlockHeight
|
||||
|
||||
if synchronizer.latestState.latestBlockHeight > 0 {
|
||||
latestBlockHeight = synchronizer.latestState.latestBlockHeight
|
||||
} else {
|
||||
latestBlockHeight = try await synchronizer.latestHeight()
|
||||
}
|
||||
|
||||
return latestBlockHeight
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue