ios: migration enhancements (#3893)

* onion check

* alert and log

* correction

* refactor

* change

* refactor

* enum

* footer

* remove non-needed directory if no migration

* naming

* back

* rename everything

---------

Co-authored-by: Avently <avently@local>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
Stanislav Dmitrenko
2024-03-12 23:25:06 +07:00
committed by GitHub
parent 96fba950ff
commit d3b255b7cb
7 changed files with 109 additions and 106 deletions
+1 -1
View File
@@ -95,7 +95,7 @@ final class ChatModel: ObservableObject {
@Published var remoteCtrlSession: RemoteCtrlSession?
// currently showing invitation
@Published var showingInvitation: ShowingInvitation?
@Published var migrationState: MigrationFromAnotherDeviceState? = MigrationFromAnotherDeviceState.transform()
@Published var migrationState: MigrationToState? = MigrationToDeviceState.makeMigrationState()
// audio recording and playback
@Published var stopPreviousRecPlay: URL? = nil // coordinates currently playing source
@Published var draft: ComposeState?
@@ -1,5 +1,5 @@
//
// MigrateToAnotherDevice.swift
// MigrateFromDevice.swift
// SimpleX (iOS)
//
// Created by Avently on 14.02.2024.
@@ -9,7 +9,7 @@
import SwiftUI
import SimpleXChat
private enum MigrationToState: Equatable {
private enum MigrationFromState: Equatable {
case chatStopInProgress
case chatStopFailed(reason: String)
case passphraseNotSet
@@ -23,7 +23,7 @@ private enum MigrationToState: Equatable {
case finished(chatDeletion: Bool)
}
private enum MigrateToAnotherDeviceViewAlert: Identifiable {
private enum MigrateFromDeviceViewAlert: Identifiable {
case deleteChat(_ title: LocalizedStringKey = "Delete chat profile?", _ text: LocalizedStringKey = "This action cannot be undone - your profile, contacts, messages and files will be irreversibly lost.")
case startChat(_ title: LocalizedStringKey = "Start chat?", _ text: LocalizedStringKey = "Warning: starting chat on multiple devices is not supported and will cause message delivery failures")
@@ -51,15 +51,15 @@ private enum MigrateToAnotherDeviceViewAlert: Identifiable {
}
}
struct MigrateToAnotherDevice: View {
struct MigrateFromDevice: View {
@EnvironmentObject var m: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
@Binding var showSettings: Bool
@Binding var showProgressOnSettings: Bool
@State private var migrationState: MigrationToState = .chatStopInProgress
@State private var migrationState: MigrationFromState = .chatStopInProgress
@State private var useKeychain = storeDBPassphraseGroupDefault.get()
@AppStorage(GROUP_DEFAULT_INITIAL_RANDOM_DB_PASSPHRASE, store: groupDefaults) private var initialRandomDBPassphrase: Bool = false
@State private var alert: MigrateToAnotherDeviceViewAlert?
@State private var alert: MigrateFromDeviceViewAlert?
@State private var authorized = !UserDefaults.standard.bool(forKey: DEFAULT_PERFORM_LA)
private let tempDatabaseUrl = urlForTemporaryDatabase()
@State private var chatReceiver: MigrationChatReceiver? = nil
@@ -108,11 +108,8 @@ struct MigrateToAnotherDevice: View {
})
.onChange(of: migrationState) { state in
backDisabled = switch migrationState {
case .archiving: true
case .linkCreation: true
case .linkShown: true
case .finished: true
default: false
case .chatStopInProgress, .archiving, .linkShown, .finished: true
case .chatStopFailed, .passphraseNotSet, .passphraseConfirmation, .uploadConfirmation, .uploadProgress, .uploadFailed, .linkCreation: false
}
}
.onAppear {
@@ -120,7 +117,7 @@ struct MigrateToAnotherDevice: View {
}
.onDisappear {
Task {
if case .linkCreation = migrationState {} else if case .linkShown = migrationState {} else if case .finished = migrationState {} else {
if !backDisabled {
await MainActor.run {
showProgressOnSettings = true
}
@@ -252,7 +249,7 @@ struct MigrateToAnotherDevice: View {
}
}
let ratio = Float(uploadedBytes) / Float(totalBytes)
MigrateToAnotherDevice.largeProgressView(ratio, "\(Int(ratio * 100))%", "\(ByteCountFormatter.string(fromByteCount: uploadedBytes, countStyle: .binary)) uploaded")
MigrateFromDevice.largeProgressView(ratio, "\(Int(ratio * 100))%", "\(ByteCountFormatter.string(fromByteCount: uploadedBytes, countStyle: .binary)) uploaded")
}
.onAppear {
startUploading(totalBytes, archivePath)
@@ -306,7 +303,10 @@ struct MigrateToAnotherDevice: View {
}
}
} footer: {
Text("Choose _Migrate from another device_ on the new device and scan QR code.")
VStack(alignment: .leading, spacing: 16) {
Text("**Warning**: the archive will be removed.")
Text("Choose _Migrate from another device_ on the new device and scan QR code.")
}
.font(.callout)
}
Section("Show QR code") {
@@ -498,6 +498,9 @@ struct MigrateToAnotherDevice: View {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
migrationState = .linkShown(fileId: fileTransferMeta.fileId, link: data.addToLink(link: rcvURIs[0]), archivePath: archivePath, ctrl: ctrl)
}
case .sndFileError:
alert = .error(title: "Upload failed", error: "Check your internet connection and try again")
migrationState = .uploadFailed(totalBytes: totalBytes, archivePath: archivePath)
default:
logger.debug("unsupported event: \(msg.responseType)")
}
@@ -587,12 +590,12 @@ struct MigrateToAnotherDevice: View {
}
private struct PassphraseConfirmationView: View {
@Binding var migrationState: MigrationToState
@Binding var migrationState: MigrationFromState
@State private var useKeychain = storeDBPassphraseGroupDefault.get()
@State private var currentKey: String = ""
@State private var verifyingPassphrase: Bool = false
@FocusState private var keyboardVisible: Bool
@Binding var alert: MigrateToAnotherDeviceViewAlert?
@Binding var alert: MigrateFromDeviceViewAlert?
var body: some View {
ZStack {
@@ -638,13 +641,17 @@ private struct PassphraseConfirmationView: View {
await MainActor.run {
migrationState = .uploadConfirmation
}
} catch {
showErrorOnMigrationIfNeeded(.errorNotADatabase(dbFile: ""), $alert)
} catch let error {
if case .chatCmdError(_, .errorDatabase(.errorOpen(.errorNotADatabase))) = error as? ChatResponse {
showErrorOnMigrationIfNeeded(.errorNotADatabase(dbFile: ""), $alert)
} else {
alert = .error(title: "Error", error: NSLocalizedString("Error verifying passphrase:", comment: "") + " " + String(String(describing: error)))
}
}
}
}
private func showErrorOnMigrationIfNeeded(_ status: DBMigrationResult, _ alert: Binding<MigrateToAnotherDeviceViewAlert?>) {
private func showErrorOnMigrationIfNeeded(_ status: DBMigrationResult, _ alert: Binding<MigrateFromDeviceViewAlert?>) {
switch status {
case .invalidConfirmation:
alert.wrappedValue = .invalidConfirmation()
@@ -720,8 +727,8 @@ private class MigrationChatReceiver {
}
}
struct MigrateToAnotherDevice_Previews: PreviewProvider {
struct MigrateFromDevice_Previews: PreviewProvider {
static var previews: some View {
MigrateToAnotherDevice(showSettings: Binding.constant(true), showProgressOnSettings: Binding.constant(false))
MigrateFromDevice(showSettings: Binding.constant(true), showProgressOnSettings: Binding.constant(false))
}
}
@@ -1,5 +1,5 @@
//
// MigrateFromAnotherDevice.swift
// MigrateToDevice.swift
// SimpleX (iOS)
//
// Created by Avently on 23.02.2024.
@@ -9,56 +9,47 @@
import SwiftUI
import SimpleXChat
enum MigrationFromAnotherDeviceState: Codable, Equatable {
enum MigrationToDeviceState: Codable, Equatable {
case downloadProgress(link: String, archiveName: String)
case archiveImport(archiveName: String)
case passphrase
func makeMigrationState() -> MigrationFromState {
var initial: MigrationFromState = .pasteOrScanLink
//logger.debug("Inited with migrationState: \(String(describing: self))")
switch self {
case let .downloadProgress(link, archiveName):
// iOS changes absolute directory every launch, check this way
let archivePath = getMigrationTempFilesDirectory().path + "/" + archiveName
initial = .downloadFailed(totalBytes: 0, link: link, archivePath: archivePath)
// Here we check whether it's needed to show migration process after app restart or not
// It's important to NOT show the process when archive was corrupted/not fully downloaded
static func makeMigrationState() -> MigrationToState? {
let state: MigrationToDeviceState? = UserDefaults.standard.string(forKey: DEFAULT_MIGRATION_TO_STAGE) != nil ? decodeJSON(UserDefaults.standard.string(forKey: DEFAULT_MIGRATION_TO_STAGE)!) : nil
var initial: MigrationToState? = .pasteOrScanLink
//logger.debug("Inited with migrationState: \(String(describing: state))")
switch state {
case nil:
initial = nil
case .downloadProgress:
// No migration happens at the moment actually since archive were not downloaded fully
logger.debug("MigrateToDevice: archive wasn't fully downloaded, removed broken file")
initial = nil
case let .archiveImport(archiveName):
let archivePath = getMigrationTempFilesDirectory().path + "/" + archiveName
initial = .archiveImportFailed(archivePath: archivePath)
case .passphrase:
initial = .passphrase(passphrase: "")
}
if initial == nil {
UserDefaults.standard.removeObject(forKey: DEFAULT_MIGRATION_TO_STAGE)
try? FileManager.default.removeItem(at: getMigrationTempFilesDirectory())
}
return initial
}
// Here we check whether it's needed to show migration process after app restart or not
// It's important to NOT show the process when archive was corrupted/not fully downloaded
static func transform() -> MigrationFromAnotherDeviceState? {
let state: MigrationFromAnotherDeviceState? = UserDefaults.standard.string(forKey: DEFAULT_MIGRATION_STAGE) != nil ? decodeJSON(UserDefaults.standard.string(forKey: DEFAULT_MIGRATION_STAGE)!) : nil
if case let .downloadProgress(_, archiveName) = state {
// iOS changes absolute directory every launch, check this way
let archivePath = getMigrationTempFilesDirectory().path + "/" + archiveName
try? FileManager.default.removeItem(atPath: archivePath)
UserDefaults.standard.removeObject(forKey: DEFAULT_MIGRATION_STAGE)
// No migration happens at the moment actually since archive were not downloaded fully
logger.debug("MigrateFromDevice: archive wasn't fully downloaded, removed broken file")
return nil
}
return state
}
static func save(_ state: MigrationFromAnotherDeviceState?, apply: (MigrationFromAnotherDeviceState?) -> Void) {
static func save(_ state: MigrationToDeviceState?) {
if let state {
UserDefaults.standard.setValue(encodeJSON(state), forKey: DEFAULT_MIGRATION_STAGE)
UserDefaults.standard.setValue(encodeJSON(state), forKey: DEFAULT_MIGRATION_TO_STAGE)
} else {
UserDefaults.standard.removeObject(forKey: DEFAULT_MIGRATION_STAGE)
UserDefaults.standard.removeObject(forKey: DEFAULT_MIGRATION_TO_STAGE)
}
apply(state)
}
}
enum MigrationFromState: Equatable {
enum MigrationToState: Equatable {
case pasteOrScanLink
case linkDownloading(link: String)
case downloadProgress(downloadedBytes: Int64, totalBytes: Int64, fileId: Int64, link: String, archivePath: String, ctrl: chat_ctrl?)
@@ -71,7 +62,7 @@ enum MigrationFromState: Equatable {
case onion(appSettings: AppSettings)
}
private enum MigrateFromAnotherDeviceViewAlert: Identifiable {
private enum MigrateToDeviceViewAlert: Identifiable {
case chatImportedWithErrors(title: LocalizedStringKey = "Chat database imported",
text: LocalizedStringKey = "Some non-fatal errors occurred during import - you may see Chat console for more details.")
@@ -98,13 +89,13 @@ private enum MigrateFromAnotherDeviceViewAlert: Identifiable {
}
}
struct MigrateFromAnotherDevice: View {
struct MigrateToDevice: View {
@EnvironmentObject var m: ChatModel
@Environment(\.dismiss) var dismiss: DismissAction
@AppStorage(DEFAULT_DEVELOPER_TOOLS) private var developerTools = false
@State var migrationState: MigrationFromState
@Binding var migrationState: MigrationToState?
@State private var useKeychain = storeDBPassphraseGroupDefault.get()
@State private var alert: MigrateFromAnotherDeviceViewAlert?
@State private var alert: MigrateToDeviceViewAlert?
private let tempDatabaseUrl = urlForTemporaryDatabase()
@State private var chatReceiver: MigrationChatReceiver? = nil
// Prevent from hiding the view until migration is finished or app deleted
@@ -114,6 +105,7 @@ struct MigrateFromAnotherDevice: View {
var body: some View {
VStack {
switch migrationState {
case nil: EmptyView()
case .pasteOrScanLink:
pasteOrScanLinkView()
case let .linkDownloading(link):
@@ -138,18 +130,14 @@ struct MigrateFromAnotherDevice: View {
}
.onAppear {
backDisabled = switch migrationState {
case .linkDownloading: false
case .downloadProgress: false
case .archiveImportFailed: false
default: m.migrationState != nil
case nil, .pasteOrScanLink, .linkDownloading, .downloadProgress, .downloadFailed, .archiveImportFailed: false
case .archiveImport, .passphrase, .migrationConfirmation, .migration, .onion: true
}
}
.onChange(of: migrationState) { state in
backDisabled = switch state {
case .linkDownloading: false
case .downloadProgress: false
case .archiveImportFailed: false
default: m.migrationState != nil
case nil, .pasteOrScanLink, .linkDownloading, .downloadProgress, .downloadFailed, .archiveImportFailed: false
case .archiveImport, .passphrase, .migrationConfirmation, .migration, .onion: true
}
}
.onDisappear {
@@ -164,7 +152,7 @@ struct MigrateFromAnotherDevice: View {
chatReceiver?.stopAndCleanUp()
if !backDisabled {
try? FileManager.default.removeItem(at: getMigrationTempFilesDirectory())
MigrationFromAnotherDeviceState.save(nil) { m.migrationState = $0 }
MigrationToDeviceState.save(nil)
}
}
}
@@ -255,7 +243,7 @@ struct MigrateFromAnotherDevice: View {
}
}
let ratio = Float(downloadedBytes) / Float(max(totalBytes, 1))
MigrateToAnotherDevice.largeProgressView(ratio, "\(Int(ratio * 100))%", "\(ByteCountFormatter.string(fromByteCount: downloadedBytes, countStyle: .binary)) downloaded")
MigrateFromDevice.largeProgressView(ratio, "\(Int(ratio * 100))%", "\(ByteCountFormatter.string(fromByteCount: downloadedBytes, countStyle: .binary)) downloaded")
}
}
@@ -280,7 +268,7 @@ struct MigrateFromAnotherDevice: View {
.onAppear {
chatReceiver?.stopAndCleanUp()
try? FileManager.default.removeItem(atPath: archivePath)
MigrationFromAnotherDeviceState.save(nil) { m.migrationState = $0 }
MigrationToDeviceState.save(nil)
}
}
@@ -446,11 +434,16 @@ struct MigrateFromAnotherDevice: View {
switch msg {
case let .rcvFileProgressXFTP(_, _, receivedSize, totalSize, rcvFileTransfer):
migrationState = .downloadProgress(downloadedBytes: receivedSize, totalBytes: totalSize, fileId: rcvFileTransfer.fileId, link: link, archivePath: archivePath, ctrl: ctrl)
MigrationFromAnotherDeviceState.save(.downloadProgress(link: link, archiveName: URL(fileURLWithPath: archivePath).lastPathComponent)) { m.migrationState = $0 }
MigrationToDeviceState.save(.downloadProgress(link: link, archiveName: URL(fileURLWithPath: archivePath).lastPathComponent))
case .rcvStandaloneFileComplete:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
migrationState = .archiveImport(archivePath: archivePath)
MigrationFromAnotherDeviceState.save(.archiveImport(archiveName: URL(fileURLWithPath: archivePath).lastPathComponent)) { m.migrationState = $0 }
// User closed the whole screen before new state was saved
if migrationState == nil {
MigrationToDeviceState.save(nil)
} else {
migrationState = .archiveImport(archivePath: archivePath)
MigrationToDeviceState.save(.archiveImport(archiveName: URL(fileURLWithPath: archivePath).lastPathComponent))
}
}
case .rcvFileError:
alert = .error(title: "Download failed", error: "File was deleted or link is invalid")
@@ -487,7 +480,7 @@ struct MigrateFromAnotherDevice: View {
}
await MainActor.run {
migrationState = .passphrase(passphrase: "")
MigrationFromAnotherDeviceState.save(.passphrase) { m.migrationState = $0 }
MigrationToDeviceState.save(.passphrase)
}
} catch let error {
await MainActor.run {
@@ -523,11 +516,12 @@ struct MigrateFromAnotherDevice: View {
resetChatCtrl()
try initializeChat(start: false, confirmStart: false, dbKey: passphrase, refreshInvitations: true, confirmMigrations: confirmation)
var appSettings = try apiGetAppSettings(settings: AppSettings.current.prepareForExport())
let hasOnionConfigured = appSettings.networkConfig?.socksProxy != nil || appSettings.networkConfig?.hostMode == .onionHost
appSettings.networkConfig?.socksProxy = nil
appSettings.networkConfig?.hostMode = .publicHost
appSettings.networkConfig?.requiredHostMode = true
await MainActor.run {
if appSettings.networkConfig?.hostMode == .onionViaSocks || appSettings.networkConfig?.hostMode == .onionHost || appSettings.networkConfig?.socksProxy != nil {
appSettings.networkConfig?.socksProxy = nil
appSettings.networkConfig?.hostMode = .publicHost
appSettings.networkConfig?.requiredHostMode = true
if hasOnionConfigured {
migrationState = .onion(appSettings: appSettings)
} else {
finishMigration(appSettings)
@@ -543,7 +537,7 @@ struct MigrateFromAnotherDevice: View {
private func finishMigration(_ appSettings: AppSettings) {
do {
try? FileManager.default.removeItem(at: getMigrationTempFilesDirectory())
MigrationFromAnotherDeviceState.save(nil) { m.migrationState = $0 }
MigrationToDeviceState.save(nil)
appSettings.importIntoApp()
try SimpleX.startChat(refreshInvitations: true)
AlertManager.shared.showAlertMsg(title: "Chat migrated!", message: "Finalize migration on another device.")
@@ -569,12 +563,12 @@ struct MigrateFromAnotherDevice: View {
}
private struct PassphraseEnteringView: View {
@Binding var migrationState: MigrationFromState
@Binding var migrationState: MigrationToState?
@State private var useKeychain = true
@State var currentKey: String
@State private var verifyingPassphrase: Bool = false
@FocusState private var keyboardVisible: Bool
@Binding var alert: MigrateFromAnotherDeviceViewAlert?
@Binding var alert: MigrateToDeviceViewAlert?
var body: some View {
ZStack {
@@ -643,7 +637,7 @@ private struct PassphraseEnteringView: View {
}
}
private func showErrorOnMigrationIfNeeded(_ status: DBMigrationResult, _ alert: Binding<MigrateFromAnotherDeviceViewAlert?>) {
private func showErrorOnMigrationIfNeeded(_ status: DBMigrationResult, _ alert: Binding<MigrateToDeviceViewAlert?>) {
switch status {
case .invalidConfirmation:
alert.wrappedValue = .invalidConfirmation()
@@ -713,8 +707,8 @@ private class MigrationChatReceiver {
}
}
struct MigrateFromAnotherDevice_Previews: PreviewProvider {
struct MigrateToDevice_Previews: PreviewProvider {
static var previews: some View {
MigrateFromAnotherDevice(migrationState: .pasteOrScanLink)
MigrateToDevice(migrationState: Binding.constant(.pasteOrScanLink))
}
}
@@ -13,8 +13,6 @@ struct SimpleXInfo: View {
@EnvironmentObject var m: ChatModel
@Environment(\.colorScheme) var colorScheme: ColorScheme
@State private var showHowItWorks = false
@State private var migrationState: MigrationFromState? = nil
@State private var migrateFromAnotherDevice: Bool = false
var onboarding: Bool
var body: some View {
@@ -49,8 +47,7 @@ struct SimpleXInfo: View {
Spacer()
Button {
migrationState = nil
migrateFromAnotherDevice = true
m.migrationState = .pasteOrScanLink
} label: {
Label("Migrate from another device", systemImage: "tray.and.arrow.down")
.font(.subheadline)
@@ -71,16 +68,15 @@ struct SimpleXInfo: View {
}
.frame(minHeight: g.size.height)
}
.onAppear {
if m.migrationState != nil {
migrationState = m.migrationState?.makeMigrationState()
migrateFromAnotherDevice = true
}
}
.sheet(isPresented: $migrateFromAnotherDevice) {
.sheet(isPresented: Binding(
get: { m.migrationState != nil },
set: { _ in
m.migrationState = nil
MigrationToDeviceState.save(nil) }
)) {
NavigationView {
VStack(alignment: .leading) {
MigrateFromAnotherDevice(migrationState: migrationState ?? .pasteOrScanLink)
MigrateToDevice(migrationState: $m.migrationState)
}
.navigationTitle("Migrate here")
.background(colorScheme == .light ? Color(uiColor: .tertiarySystemGroupedBackground) : .clear)
@@ -51,7 +51,8 @@ let DEFAULT_SHOW_HIDDEN_PROFILES_NOTICE = "showHiddenProfilesNotice"
let DEFAULT_SHOW_MUTE_PROFILE_ALERT = "showMuteProfileAlert"
let DEFAULT_WHATS_NEW_VERSION = "defaultWhatsNewVersion"
let DEFAULT_ONBOARDING_STAGE = "onboardingStage"
let DEFAULT_MIGRATION_STAGE = "migrationStage"
let DEFAULT_MIGRATION_TO_STAGE = "migrationToStage"
let DEFAULT_MIGRATION_FROM_STAGE = "migrationFromStage"
let DEFAULT_CUSTOM_DISAPPEARING_MESSAGE_TIME = "customDisappearingMessageTime"
let DEFAULT_SHOW_UNREAD_AND_FAVORITES = "showUnreadAndFavorites"
let DEFAULT_DEVICE_NAME_FOR_REMOTE_ACCESS = "deviceNameForRemoteAccess"
@@ -212,7 +213,7 @@ struct SettingsView: View {
}
NavigationLink {
MigrateToAnotherDevice(showSettings: $showSettings, showProgressOnSettings: $showProgress)
MigrateFromDevice(showSettings: $showSettings, showProgressOnSettings: $showProgress)
.navigationTitle("Migrate device")
.navigationBarTitleDisplayMode(.large)
} label: {
+8 -8
View File
@@ -186,8 +186,8 @@
64F1CC3B28B39D8600CD1FB1 /* IncognitoHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */; };
8C05382E2B39887E006436DC /* VideoUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C05382D2B39887E006436DC /* VideoUtils.swift */; };
8C69FE7D2B8C7D2700267E38 /* AppSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */; };
8C7D949A2B88952700B7B9E1 /* MigrateFromAnotherDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7D94992B88952700B7B9E1 /* MigrateFromAnotherDevice.swift */; };
8C7DF3202B7CDB0A00C886D0 /* MigrateToAnotherDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7DF31F2B7CDB0A00C886D0 /* MigrateToAnotherDevice.swift */; };
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */; };
8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */; };
D7197A1829AE89660055C05A /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = D7197A1729AE89660055C05A /* WebRTC */; };
D72A9088294BD7A70047C86D /* NativeTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A9087294BD7A70047C86D /* NativeTextEditor.swift */; };
D741547829AF89AF0022400A /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D741547729AF89AF0022400A /* StoreKit.framework */; };
@@ -477,8 +477,8 @@
64F1CC3A28B39D8600CD1FB1 /* IncognitoHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncognitoHelp.swift; sourceTree = "<group>"; };
8C05382D2B39887E006436DC /* VideoUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoUtils.swift; sourceTree = "<group>"; };
8C69FE7C2B8C7D2700267E38 /* AppSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettings.swift; sourceTree = "<group>"; };
8C7D94992B88952700B7B9E1 /* MigrateFromAnotherDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateFromAnotherDevice.swift; sourceTree = "<group>"; };
8C7DF31F2B7CDB0A00C886D0 /* MigrateToAnotherDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToAnotherDevice.swift; sourceTree = "<group>"; };
8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateToDevice.swift; sourceTree = "<group>"; };
8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateFromDevice.swift; sourceTree = "<group>"; };
D72A9087294BD7A70047C86D /* NativeTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NativeTextEditor.swift; sourceTree = "<group>"; };
D741547729AF89AF0022400A /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/StoreKit.framework; sourceTree = DEVELOPER_DIR; };
D741547929AF90B00022400A /* PushKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PushKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS16.1.sdk/System/Library/Frameworks/PushKit.framework; sourceTree = DEVELOPER_DIR; };
@@ -904,8 +904,8 @@
8C7D94982B8894D300B7B9E1 /* Migration */ = {
isa = PBXGroup;
children = (
8C7DF31F2B7CDB0A00C886D0 /* MigrateToAnotherDevice.swift */,
8C7D94992B88952700B7B9E1 /* MigrateFromAnotherDevice.swift */,
8C7DF31F2B7CDB0A00C886D0 /* MigrateFromDevice.swift */,
8C7D94992B88952700B7B9E1 /* MigrateToDevice.swift */,
);
path = Migration;
sourceTree = "<group>";
@@ -1141,7 +1141,7 @@
5CBD285A295711D700EC2CF4 /* ImageUtils.swift in Sources */,
6419EC562AB8BC8B004A607A /* ContextInvitingContactMemberView.swift in Sources */,
5CE4407927ADB701007B033A /* EmojiItemView.swift in Sources */,
8C7D949A2B88952700B7B9E1 /* MigrateFromAnotherDevice.swift in Sources */,
8C7D949A2B88952700B7B9E1 /* MigrateToDevice.swift in Sources */,
5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */,
5C029EAA283942EA004A9677 /* CallController.swift in Sources */,
5CBE6C142944CC12002D9531 /* ScanCodeView.swift in Sources */,
@@ -1239,7 +1239,7 @@
5CB0BA92282713FD00B3292C /* CreateProfile.swift in Sources */,
5C5F2B7027EBC704006A9D5F /* ProfileImage.swift in Sources */,
5C9329412929248A0090FFF9 /* ScanProtocolServer.swift in Sources */,
8C7DF3202B7CDB0A00C886D0 /* MigrateToAnotherDevice.swift in Sources */,
8C7DF3202B7CDB0A00C886D0 /* MigrateFromDevice.swift in Sources */,
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */,
5C93293F2928E0FD0090FFF9 /* AudioRecPlay.swift in Sources */,
5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */,
+6 -1
View File
@@ -68,14 +68,19 @@ public func chatInitTemporaryDatabase(url: URL, key: String? = nil, confirmation
public func chatInitControllerRemovingDatabases() {
let dbPath = getAppDatabasePath().path
let fm = FileManager.default
// Remove previous databases, otherwise, can be .errorNotADatabase with nil controller
try? fm.removeItem(atPath: dbPath + CHAT_DB)
try? fm.removeItem(atPath: dbPath + AGENT_DB)
let dbKey = randomDatabasePassword()
logger.debug("chatInitControllerRemovingDatabases path: \(dbPath)")
var cPath = dbPath.cString(using: .utf8)!
var cKey = dbKey.cString(using: .utf8)!
var cConfirm = MigrationConfirmation.error.rawValue.cString(using: .utf8)!
chat_migrate_init_key(&cPath, &cKey, 1, &cConfirm, 0, &chatController)
// We need only controller, not databases
let fm = FileManager.default
try? fm.removeItem(atPath: dbPath + CHAT_DB)
try? fm.removeItem(atPath: dbPath + AGENT_DB)
}