Better account deletion / logout handling of local data

This commit is contained in:
Jackson Harper
2023-12-13 14:42:46 +08:00
parent a4976a7b62
commit e318afbc0a
6 changed files with 97 additions and 8 deletions

View File

@ -0,0 +1,24 @@
import Models
import Services
import SwiftUI
import Utils
import Views
struct DeleteAccountView: View {
@EnvironmentObject var dataService: DataService
@EnvironmentObject var authenticator: Authenticator
public var body: some View {
VStack(alignment: .center) {
Text("Deleting account...")
ProgressView()
.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.task {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
authenticator.logout(dataService: dataService, isAccountDeletion: true)
}
}
}
}

View File

@ -0,0 +1,33 @@
import Models
import Services
import SwiftUI
import Utils
import Views
struct LogoutView: View {
@EnvironmentObject var dataService: DataService
@EnvironmentObject var authenticator: Authenticator
@Environment(\.openURL) var openURL
let deletedAccountConfirmationMessage = "Your account has been deleted. Additional steps may be needed if Sign in with Apple was used to register."
public var body: some View {
VStack(alignment: .center) {
Text("Logging out...")
ProgressView()
.frame(maxWidth: .infinity)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.task {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
authenticator.logout(dataService: dataService)
}
}
.alert(deletedAccountConfirmationMessage, isPresented: $authenticator.showAppleRevokeTokenAlert) {
Button("View Details") {
openURL(URL(string: "https://support.apple.com/en-us/HT210426")!)
}
Button(LocalText.dismissButton) { self.authenticator.showAppleRevokeTokenAlert = false }
}
}
}

View File

@ -196,7 +196,7 @@ struct ProfileView: View {
primaryButton: .destructive(Text(LocalText.genericConfirm)) {
dismiss()
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
authenticator.logout(dataService: dataService)
authenticator.beginLogout()
}
},
secondaryButton: .cancel()

View File

@ -52,9 +52,13 @@ struct InnerRootView: View {
if authenticator.isLoggedIn {
PrimaryContentView()
} else {
WelcomeView()
.accessibilityElement()
.accessibilityIdentifier("welcomeView")
if authenticator.isLoggingOut {
LogoutView()
} else {
WelcomeView()
.accessibilityElement()
.accessibilityIdentifier("welcomeView")
}
}
}

View File

@ -1,3 +1,4 @@
import CoreData
import Foundation
import GoogleSignIn
import Models
@ -18,6 +19,7 @@ public final class Authenticator: ObservableObject {
}
@Published public internal(set) var isLoggedIn: Bool
@Published public internal(set) var isLoggingOut = false
@Published public var showAppleRevokeTokenAlert = false
let networker: Networker
@ -37,15 +39,21 @@ public final class Authenticator: ObservableObject {
ValetKey.authToken.value()
}
public func beginLogout() {
isLoggingOut = true
isLoggedIn = false
}
public func logout(dataService: DataService, isAccountDeletion: Bool = false) {
dataService.resetLocalStorage()
clearCreds()
Authenticator.unregisterIntercomUser?()
isLoggedIn = false
showAppleRevokeTokenAlert = isAccountDeletion
EventTracker.reset()
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
dataService.resetLocalStorage()
}
isLoggedIn = false
isLoggingOut = false
}
public func clearCreds() {

View File

@ -128,6 +128,17 @@ public final class DataService: ObservableObject {
}
}
func deleteAllEntities(entityName: String, inContext context: NSManagedObjectContext) {
let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: entityName)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
do {
try context.execute(deleteRequest)
try context.save()
} catch {
print("Error deleting all \(entityName) items.", error)
}
}
private func clearDownloadedFiles() {
let relevantTypes = ["pdf", "mp3", "speechMarks"]
let fileMgr = FileManager()
@ -176,6 +187,15 @@ public final class DataService: ObservableObject {
}
public func resetLocalStorage() {
viewContext.perform {
// We want to specify the order of deleting items to better handle relationships
let entities = ["LibraryItem", "Viewer", "Filter", "Highlight", "NewsletterEmail",
"LinkedItemLabel", "RecentSearchItem", "Recommendation", "RecommendationGroup", "UserProfile"]
entities.forEach { entityName in
self.deleteAllEntities(entityName: entityName, inContext: self.viewContext)
}
}
lastItemSyncTime = Date(timeIntervalSinceReferenceDate: 0)
clearCoreData()