Merge pull request #170 from LukasKorba/163_validation_feedback

Requested changes done
This commit is contained in:
Francisco Gindre 2022-02-24 13:57:17 -03:00 committed by GitHub
commit 3b2dd7c43a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 45 additions and 10 deletions

View File

@ -14,6 +14,20 @@ enum RecoveryPhraseError: Error {
case unableToGeneratePhrase
}
struct FeedbackGenerator {
let generateFeedback: () -> Void
}
extension FeedbackGenerator {
static let haptic = FeedbackGenerator(
generateFeedback: { UINotificationFeedbackGenerator().notificationOccurred(.error) }
)
static let silent = FeedbackGenerator(
generateFeedback: { }
)
}
struct Pasteboard {
let setString: (String) -> Void
let getString: () -> String?
@ -40,6 +54,7 @@ struct BackupPhraseEnvironment {
let mainQueue: AnySchedulerOf<DispatchQueue>
let newPhrase: () -> Effect<RecoveryPhrase, RecoveryPhraseError>
let pasteboard: Pasteboard
let feedbackGenerator: FeedbackGenerator
}
extension BackupPhraseEnvironment {
@ -51,13 +66,15 @@ extension BackupPhraseEnvironment {
static let demo = Self(
mainQueue: DispatchQueue.main.eraseToAnyScheduler(),
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
pasteboard: .test
pasteboard: .test,
feedbackGenerator: .silent
)
static let live = Self(
mainQueue: DispatchQueue.main.eraseToAnyScheduler(),
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
pasteboard: .live
pasteboard: .live,
feedbackGenerator: .haptic
)
}

View File

@ -133,6 +133,7 @@ enum RecoveryPhraseValidationAction: Equatable {
case move(wordChip: PhraseChip.Kind, intoGroup: Int)
case succeed
case fail
case failureFeedback
case proceedToHome
case displayBackedUpPhrase
}
@ -147,7 +148,7 @@ extension RecoveryPhraseValidationReducer {
case let .move(wordChip, group):
guard
case let PhraseChip.Kind.unassigned(word) = wordChip,
case let PhraseChip.Kind.unassigned(word, color) = wordChip,
let missingChipIndex = state.missingWordChips.firstIndex(of: wordChip)
else { return .none }
@ -156,9 +157,18 @@ extension RecoveryPhraseValidationReducer {
if state.isComplete {
let value: RecoveryPhraseValidationAction = state.isValid ? .succeed : .fail
return Effect(value: value)
let effect = Effect<RecoveryPhraseValidationAction, Never>(value: value)
.delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect()
if value == .succeed {
return effect
} else {
return .concatenate(
Effect(value: .failureFeedback),
effect
)
}
}
return .none
@ -168,6 +178,9 @@ extension RecoveryPhraseValidationReducer {
case .fail:
state.route = .failure
case .failureFeedback:
environment.feedbackGenerator.generateFeedback()
case .updateRoute(let route):
state.route = route

View File

@ -15,7 +15,7 @@ extension PhraseChip {
/// Makes a PhraseChip draggable when it is of kind .unassigned
@ViewBuilder func makeDraggable() -> some View {
switch self.kind {
case .unassigned(let word):
case let .unassigned(word, _):
self.onDrag {
NSItemProvider(object: word as NSString)
}

View File

@ -126,7 +126,7 @@ extension RecoveryPhraseValidationState {
}
if let completedWord = validationWord?.word {
return .unassigned(word: completedWord)
return .unassigned(word: completedWord, color: self.coloredChipColor)
}
return .empty

View File

@ -10,7 +10,7 @@ import SwiftUI
struct PhraseChip: View {
enum Kind: Hashable {
case empty
case unassigned(word: String)
case unassigned(word: String, color: Color = Asset.Colors.Buttons.activeButton.color)
case ordered(position: Int, word: String)
}
@ -22,8 +22,8 @@ struct PhraseChip: View {
EmptyChip()
case let .ordered(position, word):
EnumeratedChip(index: position, text: word)
case .unassigned(let word):
ColoredChip(word: word)
case let .unassigned(word, color):
ColoredChip(word: word, color: color)
}
}
}

View File

@ -15,7 +15,8 @@ class RecoveryPhraseValidationTests: XCTestCase {
let testEnvironment = BackupPhraseEnvironment(
mainQueue: testScheduler.eraseToAnyScheduler(),
newPhrase: { Effect(value: .init(words: RecoveryPhrase.placeholder.words)) },
pasteboard: .test
pasteboard: .test,
feedbackGenerator: .silent
)
func testPickWordsFromMissingIndices() throws {
@ -374,6 +375,10 @@ class RecoveryPhraseValidationTests: XCTestCase {
Self.testScheduler.advance(by: 2)
store.receive(.failureFeedback) {
XCTAssertTrue($0.isComplete)
}
store.receive(.fail) {
$0.route = .failure
XCTAssertFalse($0.isValid)