Skip to content

Commit

Permalink
Bug fix transfer after network switch (#774)
Browse files Browse the repository at this point in the history
Co-authored-by: kugel3 <gustaf.kugelberg@rdx.works>
Co-authored-by: Gustaf Kugelberg <123396602+kugel3@users.noreply.github.com>
  • Loading branch information
3 people committed Sep 19, 2023
1 parent f190eab commit cd72a6a
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 92 deletions.
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import ComposableArchitecture
import Resources
import SwiftUI

extension View {
@ViewBuilder
public func showDeveloperDisclaimerBanner(_ show: Bool) -> some View {
@MainActor
public func showDeveloperDisclaimerBanner(_ store: Store<Bool, Never>) -> some View {
VStack(spacing: 0) {
if show {
DeveloperDisclaimerBanner()
WithViewStore(store, observe: { $0 }) { viewStore in
if viewStore.state {
DeveloperDisclaimerBanner()
}
}
self
}
}
}

// MARK: - DeveloperDisclaimerBanner
struct DeveloperDisclaimerBanner: View {
var body: some View {
public struct DeveloperDisclaimerBanner: View {
public var body: some View {
Text(L10n.Common.developerDisclaimerText)
.frame(maxWidth: .infinity, alignment: .center)
.padding(.small3)
.background(Color.app.orange2)
.textStyle(.body2HighImportance)
}

init() {}
public init() {}
}
3 changes: 3 additions & 0 deletions Sources/Core/FeaturePrelude/FeatureReducer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,6 @@ extension FeatureAction: Hashable where Feature.ViewAction: Hashable, Feature.Ch
}
}
}

/// For scoping to an actionless childstore
public func actionless<T>(never: Never) -> T {}
109 changes: 47 additions & 62 deletions Sources/Features/AppFeature/App+View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,20 @@ import OnboardingFeature
import SplashFeature

extension App.State {
var viewState: App.ViewState {
.init(
isOnMainnet: isOnMainnet,
hasMainnetEverBeenLive: hasMainnetEverBeenLive,
isCurrentlyOnboardingUser: isCurrentlyOnboardingUser
)
public var showIsUsingTestnetBanner: Bool {
guard hasMainnetEverBeenLive else {
return false
}
if isCurrentlyOnboardingUser {
return false
}

return !isOnMainnet
}
}

// MARK: - App.View
extension App {
public struct ViewState: Equatable {
let isOnMainnet: Bool
let hasMainnetEverBeenLive: Bool
let isCurrentlyOnboardingUser: Bool

var showIsUsingTestnetBanner: Bool {
guard hasMainnetEverBeenLive else {
return false
}
if isCurrentlyOnboardingUser {
return false
}

return !isOnMainnet
}
}

@MainActor
public struct View: SwiftUI.View {
private let store: StoreOf<App>
Expand All @@ -43,49 +29,48 @@ extension App {
}

public var body: some SwiftUI.View {
WithViewStore(store, observe: \.viewState, send: { .view($0) }) { viewStore in
SwitchStore(store.scope(state: \.root, action: Action.child)) { state in
switch state {
case .main:
CaseLet(
/App.State.Root.main,
action: App.ChildAction.main,
then: { Main.View(store: $0) }
)
let bannerStore = store.scope(state: \.showIsUsingTestnetBanner, action: actionless)
SwitchStore(store.scope(state: \.root, action: Action.child)) { state in
switch state {
case .main:
CaseLet(
/App.State.Root.main,
action: App.ChildAction.main,
then: { Main.View(store: $0) }
)

case .onboardingCoordinator:
CaseLet(
/App.State.Root.onboardingCoordinator,
action: App.ChildAction.onboardingCoordinator,
then: { OnboardingCoordinator.View(store: $0) }
)
case .onboardingCoordinator:
CaseLet(
/App.State.Root.onboardingCoordinator,
action: App.ChildAction.onboardingCoordinator,
then: { OnboardingCoordinator.View(store: $0) }
)

case .splash:
CaseLet(
/App.State.Root.splash,
action: App.ChildAction.splash,
then: { Splash.View(store: $0) }
)
case .onboardTestnetUserToMainnet:
CaseLet(
/App.State.Root.onboardTestnetUserToMainnet,
action: App.ChildAction.onboardTestnetUserToMainnet,
then: { CreateAccountCoordinator.View(store: $0) }
)
}
}
.tint(.app.gray1)
.alert(
store: store.scope(state: \.$alert, action: { .view(.alert($0)) }),
state: /App.Alerts.State.incompatibleProfileErrorAlert,
action: App.Alerts.Action.incompatibleProfileErrorAlert
)
.task { @MainActor in
await viewStore.send(.task).finish()
case .splash:
CaseLet(
/App.State.Root.splash,
action: App.ChildAction.splash,
then: { Splash.View(store: $0) }
)
case .onboardTestnetUserToMainnet:
CaseLet(
/App.State.Root.onboardTestnetUserToMainnet,
action: App.ChildAction.onboardTestnetUserToMainnet,
then: { CreateAccountCoordinator.View(store: $0) }
)
}
.showDeveloperDisclaimerBanner(viewStore.showIsUsingTestnetBanner)
.presentsLoadingViewOverlay()
}
.tint(.app.gray1)
.alert(
store: store.scope(state: \.$alert, action: { .view(.alert($0)) }),
state: /App.Alerts.State.incompatibleProfileErrorAlert,
action: App.Alerts.Action.incompatibleProfileErrorAlert
)
.task { @MainActor in
await store.send(.view(.task)).finish()
}
.showDeveloperDisclaimerBanner(bannerStore)
.presentsLoadingViewOverlay()
}
}
}
Expand Down
33 changes: 14 additions & 19 deletions Sources/Features/AssetTransferFeature/AssetTransfer+View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,22 @@ extension AssetTransfer.State {
var viewState: AssetTransfer.ViewState {
.init(
canSendTransferRequest: canSendTransferRequest,
message: message,
isMainnetAccount: isMainnetAccount,
hasMainnetEverBeenLive: hasMainnetEverBeenLive
message: message
)
}

var showIsUsingTestnetBanner: Bool {
guard hasMainnetEverBeenLive else {
return false
}
return !isMainnetAccount
}
}

extension AssetTransfer {
public struct ViewState: Equatable {
let canSendTransferRequest: Bool
let message: AssetTransferMessage.State?
let isMainnetAccount: Bool
let hasMainnetEverBeenLive: Bool

var showIsUsingTestnetBanner: Bool {
guard hasMainnetEverBeenLive else {
return false
}
return !isMainnetAccount
}
}

@MainActor
Expand Down Expand Up @@ -104,14 +100,13 @@ extension AssetTransfer {
}

public var body: some SwiftUI.View {
WithViewStore(store, observe: \.viewState) { viewStore in
WithNavigationBar {
viewStore.send(.view(.closeButtonTapped))
} content: {
View(store: store)
}
.showDeveloperDisclaimerBanner(viewStore.showIsUsingTestnetBanner)
let bannerStore = store.scope(state: \.showIsUsingTestnetBanner, action: actionless)
WithNavigationBar {
store.send(.view(.closeButtonTapped))
} content: {
View(store: store)
}
.showDeveloperDisclaimerBanner(bannerStore)
}
}
}
8 changes: 4 additions & 4 deletions Tests/Features/AppFeatureTests/AppFeatureTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ final class AppFeatureTests: TestCase {
await store.receive(.internal(.toOnboarding(hasMainnetEverBeenLive: false))) {
$0.root = .onboardingCoordinator(.init(hasMainnetEverBeenLive: false))
}
XCTAssertFalse(store.state.viewState.showIsUsingTestnetBanner)
XCTAssertFalse(store.state.showIsUsingTestnetBanner)
}

func test_splash__GIVEN__an_existing_profile__WHEN__existing_profile_loaded__THEN__we_navigate_to_main() async throws {
Expand Down Expand Up @@ -75,7 +75,7 @@ final class AppFeatureTests: TestCase {

// then
await store.receive(.internal(.currentGatewayChanged(to: .default)))
XCTAssertFalse(store.state.viewState.showIsUsingTestnetBanner)
XCTAssertFalse(store.state.showIsUsingTestnetBanner)
await store.send(.child(.splash(.delegate(.completed(.newUser, accountRecoveryNeeded: false, hasMainnetEverBeenLive: false))))) {
$0.root = .onboardingCoordinator(.init(hasMainnetEverBeenLive: false))
}
Expand Down Expand Up @@ -109,7 +109,7 @@ final class AppFeatureTests: TestCase {

// then
await store.receive(.internal(.currentGatewayChanged(to: .default)))
XCTAssertFalse(store.state.viewState.showIsUsingTestnetBanner)
XCTAssertFalse(store.state.showIsUsingTestnetBanner)
await store.send(.child(.splash(.delegate(.completed(outcome, accountRecoveryNeeded: false, hasMainnetEverBeenLive: false))))) {
$0.root = .onboardingCoordinator(.init(hasMainnetEverBeenLive: false))
}
Expand Down Expand Up @@ -190,7 +190,7 @@ final class AppFeatureTests: TestCase {
let outcome = LoadProfileOutcome.usersExistingProfileCouldNotBeLoaded(failure: .profileVersionOutdated(json: Data([0xDE, 0xAD]), version: badVersion))

await store.receive(.internal(.currentGatewayChanged(to: .default)))
XCTAssertFalse(store.state.viewState.showIsUsingTestnetBanner)
XCTAssertFalse(store.state.showIsUsingTestnetBanner)
await store.send(.child(.splash(.delegate(.completed(outcome, accountRecoveryNeeded: false, hasMainnetEverBeenLive: false))))) {
$0.alert = .incompatibleProfileErrorAlert(
.init(
Expand Down

0 comments on commit cd72a6a

Please sign in to comment.