From be558f00bed07368c6a250578353537d905e95ed Mon Sep 17 00:00:00 2001 From: Lukas Korba Date: Mon, 7 Nov 2022 11:58:56 +0100 Subject: [PATCH] [#464] Migrate MultilineTextField to ReducerProtocol (#476) - MultilineTextField migrated to ReducerProtocol - unit and snapshot tests fixed --- secant/Features/SendFlow/SendFlowStore.swift | 12 +- .../MultiLineTextFieldStore.swift | 114 ++++++++---------- .../MultiLineTextFieldTests.swift | 45 +++---- secantTests/SendTests/SendTests.swift | 2 +- 4 files changed, 76 insertions(+), 97 deletions(-) diff --git a/secant/Features/SendFlow/SendFlowStore.swift b/secant/Features/SendFlow/SendFlowStore.swift index a53230a..2d46493 100644 --- a/secant/Features/SendFlow/SendFlowStore.swift +++ b/secant/Features/SendFlow/SendFlowStore.swift @@ -18,6 +18,7 @@ typealias AnyTransactionAddressTextFieldReducer = AnyReducer< TransactionAddressTextFieldReducer.Action, SendFlowEnvironment > +typealias AnyMultiLineTextFieldReducer = AnyReducer // MARK: - State @@ -32,7 +33,7 @@ struct SendFlowState: Equatable { var addMemoState: Bool var isSendingTransaction = false - var memoState: MultiLineTextFieldState + var memoState: MultiLineTextFieldReducer.State var route: Route? var shieldedBalance = WalletBalance.zero var transactionAddressInputState: TransactionAddressTextFieldReducer.State @@ -83,7 +84,7 @@ struct SendFlowState: Equatable { enum SendFlowAction: Equatable { case addMemo(CheckCircleAction) - case memo(MultiLineTextFieldAction) + case memo(MultiLineTextFieldReducer.Action) case onAppear case onDisappear case sendConfirmationPressed @@ -247,10 +248,13 @@ extension SendFlowReducer { } ) - private static let memoReducer: SendFlowReducer = MultiLineTextFieldReducer.default.pullback( + private static let memoReducer: SendFlowReducer = AnyMultiLineTextFieldReducer { _ in + MultiLineTextFieldReducer() + } + .pullback( state: \SendFlowState.memoState, action: /SendFlowAction.memo, - environment: { _ in MultiLineTextFieldEnvironment() } + environment: { $0 } ) } diff --git a/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift b/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift index c8f9c77..cbb8e1a 100644 --- a/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift +++ b/secant/UI Components/TextFields/MultiLineTextField/MultiLineTextFieldStore.swift @@ -8,69 +8,54 @@ import Foundation import ComposableArchitecture -typealias MultiLineTextFieldReducer = Reducer -typealias MultiLineTextFieldStore = Store -typealias MultiLineTextFieldViewStore = ViewStore +typealias MultiLineTextFieldStore = Store -// MARK: - State - -struct MultiLineTextFieldState: Equatable { - /// default 0, no char limit - var charLimit = 0 - @BindableState var text = "" - - var isCharLimited: Bool { - charLimit > 0 - } - - var textLength: Int { - text.count - } - - var isValid: Bool { - charLimit > 0 - ? textLength <= charLimit - : true - } - - var charLimitText: String { - charLimit > 0 - ? isValid - ? "\(textLength)/\(charLimit)" - : "char limit exceeded \(textLength)/\(charLimit)" - : "" - } -} - -// MARK: - Action - -enum MultiLineTextFieldAction: Equatable, BindableAction { - case binding(BindingAction) -} - -// MARK: - Environment - -struct MultiLineTextFieldEnvironment { } - -extension MultiLineTextFieldEnvironment { - static let live = MultiLineTextFieldEnvironment() - - static let mock = MultiLineTextFieldEnvironment() -} - -// MARK: - Reducer - -extension MultiLineTextFieldReducer { - static let `default` = MultiLineTextFieldReducer { _, action, _ in - switch action { - case .binding(\.$text): - return .none - - case .binding: - return .none +struct MultiLineTextFieldReducer: ReducerProtocol { + struct State: Equatable { + /// default 0, no char limit + var charLimit = 0 + @BindableState var text = "" + + var isCharLimited: Bool { + charLimit > 0 + } + + var textLength: Int { + text.count + } + + var isValid: Bool { + charLimit > 0 + ? textLength <= charLimit + : true + } + + var charLimitText: String { + charLimit > 0 + ? isValid + ? "\(textLength)/\(charLimit)" + : "char limit exceeded \(textLength)/\(charLimit)" + : "" + } + } + + enum Action: Equatable, BindableAction { + case binding(BindingAction) + } + + var body: some ReducerProtocol { + BindingReducer() + + Reduce { _, action in + switch action { + case .binding(\.$text): + return .none + + case .binding: + return .none + } } } - .binding() } // MARK: - Store @@ -78,16 +63,15 @@ extension MultiLineTextFieldReducer { extension MultiLineTextFieldStore { static let placeholder = MultiLineTextFieldStore( initialState: .placeholder, - reducer: .default, - environment: MultiLineTextFieldEnvironment() + reducer: MultiLineTextFieldReducer() ) } // MARK: - Placeholders -extension MultiLineTextFieldState { - static let placeholder: MultiLineTextFieldState = { - var state = MultiLineTextFieldState() +extension MultiLineTextFieldReducer.State { + static let placeholder: MultiLineTextFieldReducer.State = { + var state = MultiLineTextFieldReducer.State() state.text = "test" return state }() diff --git a/secantTests/MultiLineTextFieldTests/MultiLineTextFieldTests.swift b/secantTests/MultiLineTextFieldTests/MultiLineTextFieldTests.swift index f3115ce..ec4cdf7 100644 --- a/secantTests/MultiLineTextFieldTests/MultiLineTextFieldTests.swift +++ b/secantTests/MultiLineTextFieldTests/MultiLineTextFieldTests.swift @@ -12,9 +12,8 @@ import ComposableArchitecture class MultiLineTextFieldTests: XCTestCase { func testIsCharLimited() throws { let store = TestStore( - initialState: MultiLineTextFieldState(charLimit: 1), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(charLimit: 1), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -28,9 +27,8 @@ class MultiLineTextFieldTests: XCTestCase { func testIsNotCharLimited() throws { let store = TestStore( - initialState: MultiLineTextFieldState(), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -44,9 +42,8 @@ class MultiLineTextFieldTests: XCTestCase { func testTextLength() throws { let store = TestStore( - initialState: MultiLineTextFieldState(), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -61,9 +58,8 @@ class MultiLineTextFieldTests: XCTestCase { func testIsValid_CharLimit() throws { let store = TestStore( - initialState: MultiLineTextFieldState(charLimit: 4), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(charLimit: 4), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -77,9 +73,8 @@ class MultiLineTextFieldTests: XCTestCase { func testIsValid_NoCharLimit() throws { let store = TestStore( - initialState: MultiLineTextFieldState(), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -93,9 +88,8 @@ class MultiLineTextFieldTests: XCTestCase { func testIsInvalid() throws { let store = TestStore( - initialState: MultiLineTextFieldState(charLimit: 3), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(charLimit: 3), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -109,9 +103,8 @@ class MultiLineTextFieldTests: XCTestCase { func testCharLimitText_NoCharLimit() throws { let store = TestStore( - initialState: MultiLineTextFieldState(), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -126,9 +119,8 @@ class MultiLineTextFieldTests: XCTestCase { func testCharLimitText_CharLimit_LessCharacters() throws { let store = TestStore( - initialState: MultiLineTextFieldState(charLimit: 5), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(charLimit: 5), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in @@ -143,9 +135,8 @@ class MultiLineTextFieldTests: XCTestCase { func testCharLimitText_CharLimit_Exceeded() throws { let store = TestStore( - initialState: MultiLineTextFieldState(charLimit: 3), - reducer: MultiLineTextFieldReducer.default, - environment: MultiLineTextFieldEnvironment() + initialState: MultiLineTextFieldReducer.State(charLimit: 3), + reducer: MultiLineTextFieldReducer() ) store.send(.binding(.set(\.$text, "test"))) { state in diff --git a/secantTests/SendTests/SendTests.swift b/secantTests/SendTests/SendTests.swift index 582cf40..0663af2 100644 --- a/secantTests/SendTests/SendTests.swift +++ b/secantTests/SendTests/SendTests.swift @@ -618,7 +618,7 @@ class SendTests: XCTestCase { func testInvalidForm_ExceededMemoCharLimit() throws { let sendState = SendFlowState( addMemoState: true, - memoState: MultiLineTextFieldState(charLimit: 3), + memoState: MultiLineTextFieldReducer.State(charLimit: 3), shieldedBalance: WalletBalance(verified: Zatoshi(1), total: Zatoshi(1)), transactionAddressInputState: TransactionAddressTextFieldReducer.State(