feat(android): 添加导出/导入备份功能的详细调试日志
添加日志位置: - TssRepository: exportShareBackup 和 importShareBackup 函数 - MainViewModel: exportShareBackup 和 importShareBackup 函数 - MainActivity: 文件选择器回调、LaunchedEffect、导出/导入触发点 日志标签: - [EXPORT] / [IMPORT]: Repository 和 ViewModel 层 - [EXPORT-FILE] / [IMPORT-FILE]: 文件选择器回调 - [EXPORT-EFFECT] / [IMPORT-EFFECT]: LaunchedEffect - [EXPORT-TRIGGER] / [IMPORT-TRIGGER]: 用户操作触发点 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c002640911
commit
7b3d28c957
|
|
@ -123,57 +123,93 @@ fun TssPartyApp(
|
||||||
val createDocumentLauncher = rememberLauncherForActivityResult(
|
val createDocumentLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.CreateDocument(ShareBackup.MIME_TYPE)
|
contract = ActivityResultContracts.CreateDocument(ShareBackup.MIME_TYPE)
|
||||||
) { uri: Uri? ->
|
) { uri: Uri? ->
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] ========== createDocumentLauncher callback ==========")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] uri: $uri")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] pendingExportJson isNull: ${pendingExportJson == null}")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] pendingExportJson length: ${pendingExportJson?.length ?: 0}")
|
||||||
uri?.let { targetUri ->
|
uri?.let { targetUri ->
|
||||||
pendingExportJson?.let { json ->
|
pendingExportJson?.let { json ->
|
||||||
try {
|
try {
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] Opening output stream to: $targetUri")
|
||||||
context.contentResolver.openOutputStream(targetUri)?.use { outputStream ->
|
context.contentResolver.openOutputStream(targetUri)?.use { outputStream ->
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] Writing ${json.length} bytes...")
|
||||||
outputStream.write(json.toByteArray(Charsets.UTF_8))
|
outputStream.write(json.toByteArray(Charsets.UTF_8))
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] Write completed")
|
||||||
}
|
}
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] File saved successfully!")
|
||||||
Toast.makeText(context, "备份文件已保存", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "备份文件已保存", Toast.LENGTH_SHORT).show()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
android.util.Log.e("MainActivity", "[EXPORT-FILE] Failed to save file: ${e.message}", e)
|
||||||
Toast.makeText(context, "保存失败: ${e.message}", Toast.LENGTH_LONG).show()
|
Toast.makeText(context, "保存失败: ${e.message}", Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] Clearing pendingExportJson and pendingExportAddress")
|
||||||
pendingExportJson = null
|
pendingExportJson = null
|
||||||
pendingExportAddress = null
|
pendingExportAddress = null
|
||||||
|
} ?: run {
|
||||||
|
android.util.Log.w("MainActivity", "[EXPORT-FILE] pendingExportJson is null, nothing to write!")
|
||||||
}
|
}
|
||||||
|
} ?: run {
|
||||||
|
android.util.Log.w("MainActivity", "[EXPORT-FILE] User cancelled file picker (uri is null)")
|
||||||
}
|
}
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-FILE] ========== callback finished ==========")
|
||||||
}
|
}
|
||||||
|
|
||||||
// File picker for importing backup
|
// File picker for importing backup
|
||||||
val openDocumentLauncher = rememberLauncherForActivityResult(
|
val openDocumentLauncher = rememberLauncherForActivityResult(
|
||||||
contract = ActivityResultContracts.OpenDocument()
|
contract = ActivityResultContracts.OpenDocument()
|
||||||
) { uri: Uri? ->
|
) { uri: Uri? ->
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] ========== openDocumentLauncher callback ==========")
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] uri: $uri")
|
||||||
uri?.let { sourceUri ->
|
uri?.let { sourceUri ->
|
||||||
try {
|
try {
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] Opening input stream from: $sourceUri")
|
||||||
context.contentResolver.openInputStream(sourceUri)?.use { inputStream ->
|
context.contentResolver.openInputStream(sourceUri)?.use { inputStream ->
|
||||||
val json = inputStream.bufferedReader().readText()
|
val json = inputStream.bufferedReader().readText()
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] Read ${json.length} bytes")
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] JSON preview: ${json.take(100)}...")
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] Calling viewModel.importShareBackup...")
|
||||||
viewModel.importShareBackup(json)
|
viewModel.importShareBackup(json)
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] viewModel.importShareBackup called")
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
android.util.Log.e("MainActivity", "[IMPORT-FILE] Failed to read file: ${e.message}", e)
|
||||||
Toast.makeText(context, "读取文件失败: ${e.message}", Toast.LENGTH_LONG).show()
|
Toast.makeText(context, "读取文件失败: ${e.message}", Toast.LENGTH_LONG).show()
|
||||||
}
|
}
|
||||||
|
} ?: run {
|
||||||
|
android.util.Log.w("MainActivity", "[IMPORT-FILE] User cancelled file picker (uri is null)")
|
||||||
}
|
}
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-FILE] ========== callback finished ==========")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle export result - trigger file save dialog
|
// Handle export result - trigger file save dialog
|
||||||
LaunchedEffect(pendingExportJson) {
|
LaunchedEffect(pendingExportJson) {
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-EFFECT] LaunchedEffect(pendingExportJson) triggered")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-EFFECT] pendingExportJson isNull: ${pendingExportJson == null}")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-EFFECT] pendingExportJson length: ${pendingExportJson?.length ?: 0}")
|
||||||
pendingExportJson?.let { json ->
|
pendingExportJson?.let { json ->
|
||||||
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
|
||||||
val addressSuffix = pendingExportAddress?.take(8) ?: "wallet"
|
val addressSuffix = pendingExportAddress?.take(8) ?: "wallet"
|
||||||
val fileName = "tss_backup_${addressSuffix}_$timestamp.${ShareBackup.FILE_EXTENSION}"
|
val fileName = "tss_backup_${addressSuffix}_$timestamp.${ShareBackup.FILE_EXTENSION}"
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-EFFECT] Launching file picker with filename: $fileName")
|
||||||
createDocumentLauncher.launch(fileName)
|
createDocumentLauncher.launch(fileName)
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-EFFECT] File picker launched")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle import result - show toast
|
// Handle import result - show toast
|
||||||
LaunchedEffect(importResult) {
|
LaunchedEffect(importResult) {
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-EFFECT] LaunchedEffect(importResult) triggered")
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-EFFECT] importResult: $importResult")
|
||||||
importResult?.let { result ->
|
importResult?.let { result ->
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-EFFECT] isSuccess: ${result.isSuccess}, error: ${result.error}, message: ${result.message}")
|
||||||
when {
|
when {
|
||||||
result.isSuccess -> {
|
result.isSuccess -> {
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-EFFECT] Showing success toast")
|
||||||
Toast.makeText(context, result.message ?: "导入成功", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, result.message ?: "导入成功", Toast.LENGTH_SHORT).show()
|
||||||
viewModel.clearExportImportResult()
|
viewModel.clearExportImportResult()
|
||||||
}
|
}
|
||||||
result.error != null -> {
|
result.error != null -> {
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-EFFECT] Showing error toast: ${result.error}")
|
||||||
Toast.makeText(context, result.error, Toast.LENGTH_LONG).show()
|
Toast.makeText(context, result.error, Toast.LENGTH_LONG).show()
|
||||||
viewModel.clearExportImportResult()
|
viewModel.clearExportImportResult()
|
||||||
}
|
}
|
||||||
|
|
@ -184,6 +220,7 @@ fun TssPartyApp(
|
||||||
// Track if startup is complete
|
// Track if startup is complete
|
||||||
// Use rememberSaveable to persist across configuration changes (e.g., file picker activity)
|
// Use rememberSaveable to persist across configuration changes (e.g., file picker activity)
|
||||||
var startupComplete by rememberSaveable { mutableStateOf(false) }
|
var startupComplete by rememberSaveable { mutableStateOf(false) }
|
||||||
|
android.util.Log.d("MainActivity", "[STATE] TssPartyApp composing, startupComplete: $startupComplete")
|
||||||
|
|
||||||
// Handle success messages
|
// Handle success messages
|
||||||
LaunchedEffect(uiState.successMessage) {
|
LaunchedEffect(uiState.successMessage) {
|
||||||
|
|
@ -260,17 +297,30 @@ fun TssPartyApp(
|
||||||
navController.navigate("transfer/$shareId")
|
navController.navigate("transfer/$shareId")
|
||||||
},
|
},
|
||||||
onExportBackup = { shareId, _ ->
|
onExportBackup = { shareId, _ ->
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] ========== onExportBackup called ==========")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] shareId: $shareId")
|
||||||
// Get address for filename
|
// Get address for filename
|
||||||
val share = shares.find { it.id == shareId }
|
val share = shares.find { it.id == shareId }
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] share found: ${share != null}, address: ${share?.address}")
|
||||||
pendingExportAddress = share?.address
|
pendingExportAddress = share?.address
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] pendingExportAddress set to: $pendingExportAddress")
|
||||||
// Export and save to file
|
// Export and save to file
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] Calling viewModel.exportShareBackup...")
|
||||||
viewModel.exportShareBackup(shareId) { json ->
|
viewModel.exportShareBackup(shareId) { json ->
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] exportShareBackup callback received")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] json length: ${json.length}")
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] Setting pendingExportJson...")
|
||||||
pendingExportJson = json
|
pendingExportJson = json
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] pendingExportJson set, length: ${pendingExportJson?.length}")
|
||||||
}
|
}
|
||||||
|
android.util.Log.d("MainActivity", "[EXPORT-TRIGGER] viewModel.exportShareBackup called (async)")
|
||||||
},
|
},
|
||||||
onImportBackup = {
|
onImportBackup = {
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-TRIGGER] ========== onImportBackup called ==========")
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-TRIGGER] Launching file picker...")
|
||||||
// Open file picker to select backup file
|
// Open file picker to select backup file
|
||||||
openDocumentLauncher.launch(arrayOf("*/*"))
|
openDocumentLauncher.launch(arrayOf("*/*"))
|
||||||
|
android.util.Log.d("MainActivity", "[IMPORT-TRIGGER] File picker launched")
|
||||||
},
|
},
|
||||||
onCreateWallet = {
|
onCreateWallet = {
|
||||||
navController.navigate(BottomNavItem.Create.route)
|
navController.navigate(BottomNavItem.Create.route)
|
||||||
|
|
|
||||||
|
|
@ -1958,18 +1958,39 @@ class TssRepository @Inject constructor(
|
||||||
* @return Result containing the backup JSON string
|
* @return Result containing the backup JSON string
|
||||||
*/
|
*/
|
||||||
suspend fun exportShareBackup(shareId: Long): Result<String> {
|
suspend fun exportShareBackup(shareId: Long): Result<String> {
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] ========== exportShareBackup START ==========")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] shareId: $shareId")
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] Fetching share from database...")
|
||||||
val share = shareRecordDao.getShareById(shareId)
|
val share = shareRecordDao.getShareById(shareId)
|
||||||
?: return@withContext Result.failure(Exception("钱包不存在"))
|
if (share == null) {
|
||||||
|
android.util.Log.e("TssRepository", "[EXPORT] Share not found in database!")
|
||||||
|
return@withContext Result.failure(Exception("钱包不存在"))
|
||||||
|
}
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] Share found:")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] - address: ${share.address}")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] - sessionId: ${share.sessionId}")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] - partyId: ${share.partyId}")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] - partyIndex: ${share.partyIndex}")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] - threshold: ${share.thresholdT}-of-${share.thresholdN}")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] - publicKey length: ${share.publicKey.length}")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] - encryptedShare length: ${share.encryptedShare.length}")
|
||||||
|
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] Converting to ShareBackup...")
|
||||||
val backup = ShareBackup.fromShareRecord(share.toShareRecord())
|
val backup = ShareBackup.fromShareRecord(share.toShareRecord())
|
||||||
val json = com.google.gson.Gson().toJson(backup)
|
android.util.Log.d("TssRepository", "[EXPORT] ShareBackup created, version: ${backup.version}")
|
||||||
|
|
||||||
android.util.Log.d("TssRepository", "Exported share backup for address: ${share.address}")
|
android.util.Log.d("TssRepository", "[EXPORT] Serializing to JSON...")
|
||||||
|
val json = com.google.gson.Gson().toJson(backup)
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] JSON length: ${json.length}")
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] JSON preview: ${json.take(200)}...")
|
||||||
|
|
||||||
|
android.util.Log.d("TssRepository", "[EXPORT] ========== exportShareBackup SUCCESS ==========")
|
||||||
Result.success(json)
|
Result.success(json)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
android.util.Log.e("TssRepository", "Failed to export share backup", e)
|
android.util.Log.e("TssRepository", "[EXPORT] ========== exportShareBackup FAILED ==========")
|
||||||
|
android.util.Log.e("TssRepository", "[EXPORT] Exception: ${e.javaClass.simpleName}: ${e.message}", e)
|
||||||
Result.failure(e)
|
Result.failure(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1981,19 +2002,41 @@ class TssRepository @Inject constructor(
|
||||||
* @return Result containing the imported ShareRecord
|
* @return Result containing the imported ShareRecord
|
||||||
*/
|
*/
|
||||||
suspend fun importShareBackup(backupJson: String): Result<ShareRecord> {
|
suspend fun importShareBackup(backupJson: String): Result<ShareRecord> {
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] ========== importShareBackup START ==========")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] JSON length: ${backupJson.length}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] JSON preview: ${backupJson.take(200)}...")
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] Parsing JSON to ShareBackup...")
|
||||||
val backup = com.google.gson.Gson().fromJson(backupJson, ShareBackup::class.java)
|
val backup = com.google.gson.Gson().fromJson(backupJson, ShareBackup::class.java)
|
||||||
?: return@withContext Result.failure(Exception("无效的备份文件格式"))
|
if (backup == null) {
|
||||||
|
android.util.Log.e("TssRepository", "[IMPORT] Parsed backup is null!")
|
||||||
|
return@withContext Result.failure(Exception("无效的备份文件格式"))
|
||||||
|
}
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] ShareBackup parsed successfully:")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - version: ${backup.version}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - address: ${backup.address}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - sessionId: ${backup.sessionId}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - partyId: ${backup.partyId}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - partyIndex: ${backup.partyIndex}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - threshold: ${backup.thresholdT}-of-${backup.thresholdN}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - publicKey length: ${backup.publicKey.length}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - encryptedShare length: ${backup.encryptedShare.length}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - createdAt: ${backup.createdAt}")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] - exportedAt: ${backup.exportedAt}")
|
||||||
|
|
||||||
// Check if wallet already exists
|
// Check if wallet already exists
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] Checking if wallet already exists...")
|
||||||
val existingShare = shareRecordDao.getShareByAddress(backup.address)
|
val existingShare = shareRecordDao.getShareByAddress(backup.address)
|
||||||
if (existingShare != null) {
|
if (existingShare != null) {
|
||||||
|
android.util.Log.e("TssRepository", "[IMPORT] Wallet already exists! id=${existingShare.id}")
|
||||||
return@withContext Result.failure(Exception("此钱包已存在 (地址: ${backup.address.take(10)}...)"))
|
return@withContext Result.failure(Exception("此钱包已存在 (地址: ${backup.address.take(10)}...)"))
|
||||||
}
|
}
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] Wallet does not exist, proceeding with import")
|
||||||
|
|
||||||
// Convert to entity and save
|
// Convert to entity and save
|
||||||
// CRITICAL: Preserve the original partyId from backup - this is required for signing
|
// CRITICAL: Preserve the original partyId from backup - this is required for signing
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] Converting to ShareRecordEntity...")
|
||||||
val shareRecord = backup.toShareRecord()
|
val shareRecord = backup.toShareRecord()
|
||||||
val entity = ShareRecordEntity(
|
val entity = ShareRecordEntity(
|
||||||
sessionId = shareRecord.sessionId,
|
sessionId = shareRecord.sessionId,
|
||||||
|
|
@ -2006,17 +2049,23 @@ class TssRepository @Inject constructor(
|
||||||
address = shareRecord.address,
|
address = shareRecord.address,
|
||||||
createdAt = shareRecord.createdAt
|
createdAt = shareRecord.createdAt
|
||||||
)
|
)
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] Entity created, partyId preserved: ${entity.partyId}")
|
||||||
|
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] Inserting into database...")
|
||||||
val newId = shareRecordDao.insertShare(entity)
|
val newId = shareRecordDao.insertShare(entity)
|
||||||
val savedShare = shareRecord.copy(id = newId)
|
android.util.Log.d("TssRepository", "[IMPORT] Inserted with id: $newId")
|
||||||
|
|
||||||
android.util.Log.d("TssRepository", "Imported share backup for address: ${backup.address}, partyId: ${backup.partyId}")
|
val savedShare = shareRecord.copy(id = newId)
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] ========== importShareBackup SUCCESS ==========")
|
||||||
|
android.util.Log.d("TssRepository", "[IMPORT] Imported wallet: address=${backup.address}, partyId=${backup.partyId}")
|
||||||
Result.success(savedShare)
|
Result.success(savedShare)
|
||||||
} catch (e: com.google.gson.JsonSyntaxException) {
|
} catch (e: com.google.gson.JsonSyntaxException) {
|
||||||
android.util.Log.e("TssRepository", "Invalid JSON format in backup", e)
|
android.util.Log.e("TssRepository", "[IMPORT] ========== importShareBackup FAILED (JSON Error) ==========")
|
||||||
|
android.util.Log.e("TssRepository", "[IMPORT] JsonSyntaxException: ${e.message}", e)
|
||||||
Result.failure(Exception("备份文件格式错误"))
|
Result.failure(Exception("备份文件格式错误"))
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
android.util.Log.e("TssRepository", "Failed to import share backup", e)
|
android.util.Log.e("TssRepository", "[IMPORT] ========== importShareBackup FAILED ==========")
|
||||||
|
android.util.Log.e("TssRepository", "[IMPORT] Exception: ${e.javaClass.simpleName}: ${e.message}", e)
|
||||||
Result.failure(e)
|
Result.failure(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -931,19 +931,30 @@ class MainViewModel @Inject constructor(
|
||||||
* @return The backup JSON string on success
|
* @return The backup JSON string on success
|
||||||
*/
|
*/
|
||||||
fun exportShareBackup(shareId: Long, onSuccess: (String) -> Unit) {
|
fun exportShareBackup(shareId: Long, onSuccess: (String) -> Unit) {
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] ========== exportShareBackup called ==========")
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] shareId: $shareId")
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] Setting loading state...")
|
||||||
_exportResult.value = ExportImportResult(isLoading = true)
|
_exportResult.value = ExportImportResult(isLoading = true)
|
||||||
|
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] Calling repository.exportShareBackup...")
|
||||||
val result = repository.exportShareBackup(shareId)
|
val result = repository.exportShareBackup(shareId)
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] Repository returned, isSuccess: ${result.isSuccess}")
|
||||||
result.fold(
|
result.fold(
|
||||||
onSuccess = { json ->
|
onSuccess = { json ->
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] Export succeeded, json length: ${json.length}")
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] Setting success state and calling onSuccess callback...")
|
||||||
_exportResult.value = ExportImportResult(isSuccess = true)
|
_exportResult.value = ExportImportResult(isSuccess = true)
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] Calling onSuccess callback with json...")
|
||||||
onSuccess(json)
|
onSuccess(json)
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] onSuccess callback completed")
|
||||||
},
|
},
|
||||||
onFailure = { e ->
|
onFailure = { e ->
|
||||||
|
android.util.Log.e("MainViewModel", "[EXPORT] Export failed: ${e.message}", e)
|
||||||
_exportResult.value = ExportImportResult(error = e.message ?: "导出失败")
|
_exportResult.value = ExportImportResult(error = e.message ?: "导出失败")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
android.util.Log.d("MainViewModel", "[EXPORT] ========== exportShareBackup finished ==========")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -952,27 +963,42 @@ class MainViewModel @Inject constructor(
|
||||||
* @param backupJson The backup JSON string to import
|
* @param backupJson The backup JSON string to import
|
||||||
*/
|
*/
|
||||||
fun importShareBackup(backupJson: String) {
|
fun importShareBackup(backupJson: String) {
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] ========== importShareBackup called ==========")
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] JSON length: ${backupJson.length}")
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] JSON preview: ${backupJson.take(100)}...")
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] Setting loading state...")
|
||||||
_importResult.value = ExportImportResult(isLoading = true)
|
_importResult.value = ExportImportResult(isLoading = true)
|
||||||
|
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] Calling repository.importShareBackup...")
|
||||||
val result = repository.importShareBackup(backupJson)
|
val result = repository.importShareBackup(backupJson)
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] Repository returned, isSuccess: ${result.isSuccess}")
|
||||||
result.fold(
|
result.fold(
|
||||||
onSuccess = { share ->
|
onSuccess = { share ->
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] Import succeeded:")
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] - id: ${share.id}")
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] - address: ${share.address}")
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] - partyId: ${share.partyId}")
|
||||||
_importResult.value = ExportImportResult(
|
_importResult.value = ExportImportResult(
|
||||||
isSuccess = true,
|
isSuccess = true,
|
||||||
message = "已成功导入钱包 (${share.address.take(10)}...)"
|
message = "已成功导入钱包 (${share.address.take(10)}...)"
|
||||||
)
|
)
|
||||||
// Update wallet count
|
// Update wallet count
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] Updating wallet count...")
|
||||||
_appState.update { state ->
|
_appState.update { state ->
|
||||||
state.copy(walletCount = state.walletCount + 1)
|
state.copy(walletCount = state.walletCount + 1)
|
||||||
}
|
}
|
||||||
// Fetch balance for the imported wallet
|
// Fetch balance for the imported wallet
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] Fetching balance...")
|
||||||
fetchBalanceForShare(share)
|
fetchBalanceForShare(share)
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] Import complete!")
|
||||||
},
|
},
|
||||||
onFailure = { e ->
|
onFailure = { e ->
|
||||||
|
android.util.Log.e("MainViewModel", "[IMPORT] Import failed: ${e.message}", e)
|
||||||
_importResult.value = ExportImportResult(error = e.message ?: "导入失败")
|
_importResult.value = ExportImportResult(error = e.message ?: "导入失败")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
android.util.Log.d("MainViewModel", "[IMPORT] ========== importShareBackup finished ==========")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue