Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to Restore From Backup flow #1170

Merged
merged 71 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
4652195
Refactor ResetWallet
kugel3 Jun 4, 2024
872ef7c
wip
kugel3 Jun 4, 2024
5d4d434
wip
kugel3 Jun 4, 2024
945aca8
wip
kugel3 Jun 5, 2024
41effd9
wip
kugel3 Jun 5, 2024
84f2e99
wip
kugel3 Jun 5, 2024
e13d995
wip
kugel3 Jun 5, 2024
58bac33
wip, with debug code
kugel3 Jun 5, 2024
790f57b
cleanup
kugel3 Jun 5, 2024
f3ef1c0
Fix TCA error
kugel3 Jun 4, 2024
baafd24
make tests build
kugel3 Jun 5, 2024
77f5626
Change when to show yellow items
kugel3 Jun 6, 2024
ac0c7e7
Remove unneeded reclaimProfile
kugel3 Jun 6, 2024
b8d86a6
Comment fix
kugel3 Jun 6, 2024
86ccf9c
Pass in profile
kugel3 Jun 6, 2024
c5b47c5
Turn off keychain sync less often
kugel3 Jun 6, 2024
b5406c3
remove unused dismiss
kugel3 Jun 6, 2024
b5edba5
add support for TCA dismiss() in fullscreen overlay
kugel3 Jun 6, 2024
4825e87
PROFILESTORE: stop emitting
kugel3 Jun 6, 2024
b7e6a43
remove cloud import
kugel3 Jun 6, 2024
fcd84e9
don't sync new profiles to icloud keychain
kugel3 Jun 6, 2024
531ff3f
Remove isInCloud
kugel3 Jun 6, 2024
f37750b
simplify
kugel3 Jun 6, 2024
c406537
remove lookupProfileSnapshotByHeader
kugel3 Jun 6, 2024
d5316cc
Delete ProfileBackupSettings
kugel3 Jun 6, 2024
895d9fd
Remove loadProfileBackups
kugel3 Jun 6, 2024
82875d9
Rename and refactor backupsclient
kugel3 Jun 6, 2024
631f155
Remove unused
kugel3 Jun 6, 2024
142b97b
saveHash -> saveIdentifier
kugel3 Jun 6, 2024
30b68b7
simplify SecureStorageClient
kugel3 Jun 6, 2024
68d80d5
Simplify AppPreferencesClient
kugel3 Jun 6, 2024
bea783e
Simplify cloudbackupsclient
kugel3 Jun 6, 2024
829590e
wip claim profile
kugel3 Jun 6, 2024
f2baedd
Make import and claiming work correctly
kugel3 Jun 7, 2024
60b4406
Move loading
kugel3 Jun 7, 2024
e73e9ab
Don't stop migration if profile is missing from keychain
kugel3 Jun 7, 2024
91443f0
PROFILESTORE temp
kugel3 Jun 7, 2024
d0758d3
don't migrate if we have newer backed up
kugel3 Jun 7, 2024
d9458f5
fix problems 3 and 9
kugel3 Jun 7, 2024
e1017f5
remove duplicates
kugel3 Jun 7, 2024
eede0cb
SecurityCenterClient improvements (#1167)
matiasbzurovski Jun 7, 2024
aac177b
Stop checking header against profile
kugel3 Jun 7, 2024
0b412dd
small refactor
kugel3 Jun 7, 2024
855098f
Refine backup status
kugel3 Jun 7, 2024
671c988
wip
kugel3 Jun 7, 2024
6c0af5f
wip
kugel3 Jun 7, 2024
11de1f1
wip
kugel3 Jun 7, 2024
b0f1966
wip
kugel3 Jun 7, 2024
f470f44
fixed
kugel3 Jun 7, 2024
fe183f9
matias fix
kugel3 Jun 7, 2024
d9a2d7a
migration speedup
kugel3 Jun 9, 2024
ef04213
PROFILESTORE remove ConflictingOwners
kugel3 Jun 9, 2024
1006b54
LastUSedDevice on backup cards
kugel3 Jun 9, 2024
a868f90
Fix tests
kugel3 Jun 9, 2024
a5a2e33
PROFILESTORE remove mode
kugel3 Jun 9, 2024
4c06211
fix tests
kugel3 Jun 9, 2024
b051682
Avoid a potential claim edge case issue
kugel3 Jun 10, 2024
97cbff1
Update "Last backup" logic
kugel3 Jun 10, 2024
7748ef8
subtly better
kugel3 Jun 10, 2024
c1d06fd
Fix elusive problem
kugel3 Jun 11, 2024
6d06317
check if backup file still exists
kugel3 Jun 11, 2024
b271202
bug or on purpose?
kugel3 Jun 11, 2024
4bda00a
Small improvement to Personas loading (#1169)
matiasbzurovski Jun 10, 2024
023a167
Remove push presentation from RestoreFromBackup flow
matiasbzurovski Jun 10, 2024
c06e24e
fix missing X button
matiasbzurovski Jun 10, 2024
fb1e107
[ABW-3396] Claim Wallet (#1161)
kugel3 Jun 11, 2024
d35d23b
Retroactively Update Backup Log (#1172)
kugel3 Jun 12, 2024
703050d
Fix old QR code error message (#1174)
danvleju-rdx Jun 13, 2024
e137b24
Merged main
matiasbzurovski Jun 14, 2024
2740d7d
Merge branch 'main' into mb/import-flow
matiasbzurovski Jul 10, 2024
fe4b6a1
Merge branch 'main' into mb/import-flow
GhenadieVP Jul 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public struct PersonaList: Sendable, FeatureReducer {
}

public enum InternalAction: Sendable, Equatable {
case personasLoaded(IdentifiedArrayOf<PersonaFeature.State>)
case setPersonas([Persona])
case setSecurityProblems([SecurityProblem])
}

Expand Down Expand Up @@ -80,27 +80,12 @@ public struct PersonaList: Sendable, FeatureReducer {
case personasMissingFromClient(OrderedSet<Persona.ID>)
}

/// Returns the ids of personas to include under the given strategy. nil means that all ids should be included
private func personaIDs(_ strategy: State.ReloadingStrategy) async throws -> OrderedSet<Persona.ID>? {
switch strategy {
case .all:
return nil
case let .ids(ids):
return ids
case let .dApp(dAppID):
guard let dApp = try? await authorizedDappsClient.getDetailedDapp(dAppID) else { return [] }
return OrderedSet(dApp.detailedAuthorizedPersonas.map(\.id))
}
}

public func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> {
switch internalAction {
case var .personasLoaded(personas):
personas.mutateAll { persona in
persona.securityProblemsConfig.update(problems: state.problems)
}

case let .setPersonas(personas):
state.personas = personas
.map { PersonaFeature.State(persona: $0, problems: state.problems) }
.asIdentified()
return .none

case let .setSecurityProblems(problems):
Expand Down Expand Up @@ -133,15 +118,15 @@ public struct PersonaList: Sendable, FeatureReducer {
}

private func personasEffect(state: State) -> Effect<Action> {
.run { [strategy = state.strategy, problems = state.problems] send in
.run { [strategy = state.strategy] send in
for try await personas in await personasClient.personas() {
guard !Task.isCancelled else { return }
let ids = try await personaIDs(strategy) ?? OrderedSet(validating: personas.ids)
let result = ids.compactMap { personas[id: $0] }.map { PersonaFeature.State(persona: $0, problems: problems) }
let result = ids.compactMap { personas[id: $0] }
guard result.count == ids.count else {
throw UpdatePersonaError.personasMissingFromClient(ids.subtracting(result.map(\.id)))
}
await send(.internal(.personasLoaded(result.asIdentified())))
await send(.internal(.setPersonas(result)))
}
} catch: { error, _ in
loggerGlobal.error("Failed to update personas from client, error: \(error)")
Expand All @@ -157,4 +142,17 @@ public struct PersonaList: Sendable, FeatureReducer {
}
}
}

/// Returns the ids of personas to include under the given strategy. nil means that all ids should be included
private func personaIDs(_ strategy: State.ReloadingStrategy) async throws -> OrderedSet<Persona.ID>? {
switch strategy {
case .all:
return nil
case let .ids(ids):
return ids
case let .dApp(dAppID):
guard let dApp = try? await authorizedDappsClient.getDetailedDapp(dAppID) else { return [] }
return OrderedSet(dApp.detailedAuthorizedPersonas.map(\.id))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,36 @@ extension RestoreProfileFromBackupCoordinator {
}

public var body: some SwiftUI.View {
NavigationStackStore(
store.scope(state: \.path, action: { .child(.path($0)) })
) {
path(for: store.scope(state: \.root, action: { .child(.root($0)) }))
} destination: {
path(for: $0)
}
SelectBackup.View(store: store.selectBackup)
.inNavigationStack
.destinations(with: store)
}
}
}

private extension StoreOf<RestoreProfileFromBackupCoordinator> {
var selectBackup: StoreOf<SelectBackup> {
scope(state: \.selectBackup, action: \.child.selectBackup)
}

var destination: PresentationStoreOf<RestoreProfileFromBackupCoordinator.Destination> {
func scopeState(state: State) -> PresentationState<RestoreProfileFromBackupCoordinator.Destination.State> {
state.$destination
}
return scope(state: scopeState, action: Action.destination)
}
}

@MainActor
private extension View {
func destinations(with store: StoreOf<RestoreProfileFromBackupCoordinator>) -> some View {
let destinationStore = store.destination
return importMnemonics(with: destinationStore)
}

private func path(
for store: StoreOf<RestoreProfileFromBackupCoordinator.Path>
) -> some SwiftUI.View {
SwitchStore(store) { state in
switch state {
case .selectBackup:
CaseLet(
/RestoreProfileFromBackupCoordinator.Path.State.selectBackup,
action: RestoreProfileFromBackupCoordinator.Path.Action.selectBackup,
then: { SelectBackup.View(store: $0) }
)
case .importMnemonicsFlow:
CaseLet(
/RestoreProfileFromBackupCoordinator.Path.State.importMnemonicsFlow,
action: RestoreProfileFromBackupCoordinator.Path.Action.importMnemonicsFlow,
then: { ImportMnemonicsFlowCoordinator.View(store: $0) }
)
}
}
private func importMnemonics(with destinationStore: PresentationStoreOf<RestoreProfileFromBackupCoordinator.Destination>) -> some View {
sheet(store: destinationStore.scope(state: \.importMnemonicsFlow, action: \.importMnemonicsFlow)) {
ImportMnemonicsFlowCoordinator.View(store: $0)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,38 @@ public struct ProfileSelection: Sendable, Hashable {
// MARK: - RestoreProfileFromBackupCoordinator
public struct RestoreProfileFromBackupCoordinator: Sendable, FeatureReducer {
public struct State: Sendable, Hashable {
public var root: Path.State
public var path: StackState<Path.State> = .init()
public var selectBackup = SelectBackup.State()
public var profileSelection: ProfileSelection?

public init() {
self.root = .selectBackup(.init())
}
@PresentationState
public var destination: Destination.State?
}

public struct Path: Sendable, Hashable, Reducer {
public struct Destination: DestinationReducer {
@CasePathable
public enum State: Sendable, Hashable {
case selectBackup(SelectBackup.State)
case importMnemonicsFlow(ImportMnemonicsFlowCoordinator.State)
}

@CasePathable
public enum Action: Sendable, Equatable {
case selectBackup(SelectBackup.Action)
case importMnemonicsFlow(ImportMnemonicsFlowCoordinator.Action)
}

public var body: some ReducerOf<Self> {
Scope(state: \.selectBackup, action: \.selectBackup) {
SelectBackup()
}
Scope(state: \.importMnemonicsFlow, action: \.importMnemonicsFlow) {
ImportMnemonicsFlowCoordinator()
}
}
}

public enum InternalAction: Sendable, Equatable {
case delayedAppendToPath(RestoreProfileFromBackupCoordinator.Path.State)
case startImportMnemonicsFlow(Profile)
}

@CasePathable
public enum ChildAction: Sendable, Equatable {
case root(Path.Action)
case path(StackActionOf<Path>)
case selectBackup(SelectBackup.Action)
}

public enum DelegateAction: Sendable, Equatable {
Expand All @@ -69,44 +61,50 @@ public struct RestoreProfileFromBackupCoordinator: Sendable, FeatureReducer {
public init() {}

public var body: some ReducerOf<Self> {
Scope(state: \.root, action: \.child.root) {
Path()
Scope(state: \.selectBackup, action: \.child.selectBackup) {
SelectBackup()
}

Reduce(core)
.forEach(\.path, action: \.child.path) {
Path()
.ifLet(destinationPath, action: /Action.destination) {
Destination()
}
}

public func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> {
switch internalAction {
case let .delayedAppendToPath(destination):
state.path.append(destination)
return .none
}
}
private let destinationPath: WritableKeyPath<State, PresentationState<Destination.State>> = \.$destination

public func reduce(into state: inout State, childAction: ChildAction) -> Effect<Action> {
switch childAction {
case let .root(.selectBackup(.delegate(.selectedProfile(profile, containsLegacyP2PLinks)))):
case let .selectBackup(.delegate(.selectedProfile(profile, containsLegacyP2PLinks))):
state.profileSelection = .init(profile: profile, containsP2PLinks: containsLegacyP2PLinks)

return .run { send in
try? await clock.sleep(for: .milliseconds(300))
_ = await radixConnectClient.loadP2PLinksAndConnectAll()
await send(.internal(.delayedAppendToPath(
.importMnemonicsFlow(.init(context: .fromOnboarding(profile: profile)))
)))
await send(.internal(.startImportMnemonicsFlow(profile)))
}

case .root(.selectBackup(.delegate(.backToStartOfOnboarding))):
case .selectBackup(.delegate(.backToStartOfOnboarding)):
return .send(.delegate(.backToStartOfOnboarding))

case .root(.selectBackup(.delegate(.profileCreatedFromImportedBDFS))):
case .selectBackup(.delegate(.profileCreatedFromImportedBDFS)):
return .send(.delegate(.profileCreatedFromImportedBDFS))

case let .path(.element(_, action: .importMnemonicsFlow(.delegate(.finishedImportingMnemonics(skipList, _, notYetSavedNewMainBDFS))))):
default:
return .none
}
}

public func reduce(into state: inout State, internalAction: InternalAction) -> Effect<Action> {
switch internalAction {
case let .startImportMnemonicsFlow(profile):
state.destination = .importMnemonicsFlow(.init(context: .fromOnboarding(profile: profile)))
return .none
}
}

public func reduce(into state: inout State, presentedAction: Destination.Action) -> Effect<Action> {
switch presentedAction {
case let .importMnemonicsFlow(.delegate(.finishedImportingMnemonics(skipList, _, notYetSavedNewMainBDFS))):
loggerGlobal.notice("Starting import snapshot process...")
guard let profileSelection = state.profileSelection else {
preconditionFailure("Expected to have a profile")
Expand All @@ -130,8 +128,8 @@ public struct RestoreProfileFromBackupCoordinator: Sendable, FeatureReducer {
errorQueue.schedule(error)
}

case let .path(.element(_, action: .importMnemonicsFlow(.delegate(.finishedEarly(didFail))))):
state.path.removeLast()
case let .importMnemonicsFlow(.delegate(.finishedEarly(didFail))):
state.destination = nil
return .run { send in
await radixConnectClient.disconnectAll()
if didFail {
Expand Down
Loading