From 036becb5beee00059fb1b36a01356c464a4a61c2 Mon Sep 17 00:00:00 2001 From: Atridad Lahiji Date: Sun, 28 Sep 2025 02:37:03 -0600 Subject: [PATCH] 1.6.0 for Android and 1.1.0 for iOS - Finalizing Export and Import formats :) --- ...otlin-compiler-12230421336915548227.salive | 0 android/app/build.gradle.kts | 4 +- .../openclimb/data/format/BackupFormat.kt | 226 +++++++++ .../data/repository/ClimbRepository.kt | 130 ++--- .../openclimb/utils/ZipExportImportUtils.kt | 223 +++++---- android/gradle/wrapper/gradle-wrapper.jar | Bin 59203 -> 0 bytes android/test_backup/ClimbRepository.kt | 383 +++++++++++++++ ios/OpenClimb.xcodeproj/project.pbxproj | 16 +- .../UserInterfaceState.xcuserstate | Bin 115423 -> 117982 bytes ios/OpenClimb/ContentView.swift | 2 +- ios/OpenClimb/Models/BackupFormat.swift | 452 ++++++++++++++++++ ios/OpenClimb/Utils/ZipUtils.swift | 5 +- .../ViewModels/ClimbingDataManager.swift | 358 +------------- .../ViewModels/LiveActivityManager.swift | 10 +- ios/OpenClimb/Views/SessionsView.swift | 12 +- 15 files changed, 1259 insertions(+), 562 deletions(-) create mode 100644 android/.kotlin/sessions/kotlin-compiler-12230421336915548227.salive create mode 100644 android/app/src/main/java/com/atridad/openclimb/data/format/BackupFormat.kt delete mode 100644 android/gradle/wrapper/gradle-wrapper.jar create mode 100644 android/test_backup/ClimbRepository.kt create mode 100644 ios/OpenClimb/Models/BackupFormat.swift diff --git a/android/.kotlin/sessions/kotlin-compiler-12230421336915548227.salive b/android/.kotlin/sessions/kotlin-compiler-12230421336915548227.salive new file mode 100644 index 0000000..e69de29 diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 1b83931..dc0c78f 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -16,8 +16,8 @@ android { applicationId = "com.atridad.openclimb" minSdk = 31 targetSdk = 36 - versionCode = 26 - versionName = "1.5.1" + versionCode = 27 + versionName = "1.6.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/android/app/src/main/java/com/atridad/openclimb/data/format/BackupFormat.kt b/android/app/src/main/java/com/atridad/openclimb/data/format/BackupFormat.kt new file mode 100644 index 0000000..e1658a7 --- /dev/null +++ b/android/app/src/main/java/com/atridad/openclimb/data/format/BackupFormat.kt @@ -0,0 +1,226 @@ +package com.atridad.openclimb.data.format + +import com.atridad.openclimb.data.model.* +import kotlinx.serialization.Serializable + +/** Root structure for OpenClimb backup data */ +@Serializable +data class ClimbDataBackup( + val exportedAt: String, + val version: String = "2.0", + val formatVersion: String = "2.0", + val gyms: List, + val problems: List, + val sessions: List, + val attempts: List +) + +/** Platform-neutral gym representation for backup/restore */ +@Serializable +data class BackupGym( + val id: String, + val name: String, + val location: String? = null, + val supportedClimbTypes: List, + val difficultySystems: List, + val customDifficultyGrades: List = emptyList(), + val notes: String? = null, + val createdAt: String, // ISO 8601 format + val updatedAt: String // ISO 8601 format +) { + companion object { + /** Create BackupGym from native Android Gym model */ + fun fromGym(gym: Gym): BackupGym { + return BackupGym( + id = gym.id, + name = gym.name, + location = gym.location, + supportedClimbTypes = gym.supportedClimbTypes, + difficultySystems = gym.difficultySystems, + customDifficultyGrades = gym.customDifficultyGrades, + notes = gym.notes, + createdAt = gym.createdAt, + updatedAt = gym.updatedAt + ) + } + } + + /** Convert to native Android Gym model */ + fun toGym(): Gym { + return Gym( + id = id, + name = name, + location = location, + supportedClimbTypes = supportedClimbTypes, + difficultySystems = difficultySystems, + customDifficultyGrades = customDifficultyGrades, + notes = notes, + createdAt = createdAt, + updatedAt = updatedAt + ) + } +} + +/** Platform-neutral problem representation for backup/restore */ +@Serializable +data class BackupProblem( + val id: String, + val gymId: String, + val name: String? = null, + val description: String? = null, + val climbType: ClimbType, + val difficulty: DifficultyGrade, + val tags: List = emptyList(), + val location: String? = null, + val imagePaths: List? = null, + val isActive: Boolean = true, + val dateSet: String? = null, // ISO 8601 format + val notes: String? = null, + val createdAt: String, // ISO 8601 format + val updatedAt: String // ISO 8601 format +) { + companion object { + /** Create BackupProblem from native Android Problem model */ + fun fromProblem(problem: Problem): BackupProblem { + return BackupProblem( + id = problem.id, + gymId = problem.gymId, + name = problem.name, + description = problem.description, + climbType = problem.climbType, + difficulty = problem.difficulty, + tags = problem.tags, + location = problem.location, + imagePaths = problem.imagePaths.ifEmpty { null }, + isActive = problem.isActive, + dateSet = problem.dateSet, + notes = problem.notes, + createdAt = problem.createdAt, + updatedAt = problem.updatedAt + ) + } + } + + /** Convert to native Android Problem model */ + fun toProblem(): Problem { + return Problem( + id = id, + gymId = gymId, + name = name, + description = description, + climbType = climbType, + difficulty = difficulty, + tags = tags, + location = location, + imagePaths = imagePaths ?: emptyList(), + isActive = isActive, + dateSet = dateSet, + notes = notes, + createdAt = createdAt, + updatedAt = updatedAt + ) + } + + /** Create a copy with updated image paths for import processing */ + fun withUpdatedImagePaths(newImagePaths: List): BackupProblem { + return copy(imagePaths = newImagePaths.ifEmpty { null }) + } +} + +/** Platform-neutral climb session representation for backup/restore */ +@Serializable +data class BackupClimbSession( + val id: String, + val gymId: String, + val date: String, // ISO 8601 format + val startTime: String? = null, // ISO 8601 format + val endTime: String? = null, // ISO 8601 format + val duration: Long? = null, // Duration in seconds + val status: SessionStatus, + val notes: String? = null, + val createdAt: String, // ISO 8601 format + val updatedAt: String // ISO 8601 format +) { + companion object { + /** Create BackupClimbSession from native Android ClimbSession model */ + fun fromClimbSession(session: ClimbSession): BackupClimbSession { + return BackupClimbSession( + id = session.id, + gymId = session.gymId, + date = session.date, + startTime = session.startTime, + endTime = session.endTime, + duration = session.duration, + status = session.status, + notes = session.notes, + createdAt = session.createdAt, + updatedAt = session.updatedAt + ) + } + } + + /** Convert to native Android ClimbSession model */ + fun toClimbSession(): ClimbSession { + return ClimbSession( + id = id, + gymId = gymId, + date = date, + startTime = startTime, + endTime = endTime, + duration = duration, + status = status, + notes = notes, + createdAt = createdAt, + updatedAt = updatedAt + ) + } +} + +/** Platform-neutral attempt representation for backup/restore */ +@Serializable +data class BackupAttempt( + val id: String, + val sessionId: String, + val problemId: String, + val result: AttemptResult, + val highestHold: String? = null, + val notes: String? = null, + val duration: Long? = null, // Duration in seconds + val restTime: Long? = null, // Rest time in seconds + val timestamp: String, // ISO 8601 format + val createdAt: String // ISO 8601 format +) { + companion object { + /** Create BackupAttempt from native Android Attempt model */ + fun fromAttempt(attempt: Attempt): BackupAttempt { + return BackupAttempt( + id = attempt.id, + sessionId = attempt.sessionId, + problemId = attempt.problemId, + result = attempt.result, + highestHold = attempt.highestHold, + notes = attempt.notes, + duration = attempt.duration, + restTime = attempt.restTime, + timestamp = attempt.timestamp, + createdAt = attempt.createdAt + ) + } + } + + /** Convert to native Android Attempt model */ + fun toAttempt(): Attempt { + return Attempt( + id = id, + sessionId = sessionId, + problemId = problemId, + result = result, + highestHold = highestHold, + notes = notes, + duration = duration, + restTime = restTime, + timestamp = timestamp, + createdAt = createdAt + ) + } +} diff --git a/android/app/src/main/java/com/atridad/openclimb/data/repository/ClimbRepository.kt b/android/app/src/main/java/com/atridad/openclimb/data/repository/ClimbRepository.kt index e4d3e0d..37acff7 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/repository/ClimbRepository.kt +++ b/android/app/src/main/java/com/atridad/openclimb/data/repository/ClimbRepository.kt @@ -2,6 +2,11 @@ package com.atridad.openclimb.data.repository import android.content.Context import com.atridad.openclimb.data.database.OpenClimbDatabase +import com.atridad.openclimb.data.format.BackupAttempt +import com.atridad.openclimb.data.format.BackupClimbSession +import com.atridad.openclimb.data.format.BackupGym +import com.atridad.openclimb.data.format.BackupProblem +import com.atridad.openclimb.data.format.ClimbDataBackup import com.atridad.openclimb.data.model.* import com.atridad.openclimb.utils.ZipExportImportUtils import java.io.File @@ -27,7 +32,6 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) suspend fun insertGym(gym: Gym) = gymDao.insertGym(gym) suspend fun updateGym(gym: Gym) = gymDao.updateGym(gym) suspend fun deleteGym(gym: Gym) = gymDao.deleteGym(gym) - fun searchGyms(query: String): Flow> = gymDao.searchGyms(query) // Problem operations fun getAllProblems(): Flow> = problemDao.getAllProblems() @@ -36,7 +40,6 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) suspend fun insertProblem(problem: Problem) = problemDao.insertProblem(problem) suspend fun updateProblem(problem: Problem) = problemDao.updateProblem(problem) suspend fun deleteProblem(problem: Problem) = problemDao.deleteProblem(problem) - fun searchProblems(query: String): Flow> = problemDao.searchProblems(query) // Session operations fun getAllSessions(): Flow> = sessionDao.getAllSessions() @@ -67,69 +70,9 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) suspend fun updateAttempt(attempt: Attempt) = attemptDao.updateAttempt(attempt) suspend fun deleteAttempt(attempt: Attempt) = attemptDao.deleteAttempt(attempt) - // ZIP Export with images - Single format for reliability - suspend fun exportAllDataToZip(directory: File? = null): File { - try { - // Collect all data with proper error handling - val allGyms = gymDao.getAllGyms().first() - val allProblems = problemDao.getAllProblems().first() - val allSessions = sessionDao.getAllSessions().first() - val allAttempts = attemptDao.getAllAttempts().first() - - // Validate data integrity before export - validateDataIntegrity(allGyms, allProblems, allSessions, allAttempts) - - val exportData = - ClimbDataExport( - exportedAt = LocalDateTime.now().toString(), - version = "2.0", - gyms = allGyms, - problems = allProblems, - sessions = allSessions, - attempts = allAttempts - ) - - // Collect all referenced image paths and validate they exist - val referencedImagePaths = allProblems.flatMap { it.imagePaths }.toSet() - val validImagePaths = - referencedImagePaths - .filter { imagePath -> - try { - val imageFile = - com.atridad.openclimb.utils.ImageUtils.getImageFile( - context, - imagePath - ) - imageFile.exists() && imageFile.length() > 0 - } catch (e: Exception) { - false - } - } - .toSet() - - // Log any missing images for debugging - val missingImages = referencedImagePaths - validImagePaths - if (missingImages.isNotEmpty()) { - android.util.Log.w( - "ClimbRepository", - "Some referenced images are missing: $missingImages" - ) - } - - return ZipExportImportUtils.createExportZip( - context = context, - exportData = exportData, - referencedImagePaths = validImagePaths, - directory = directory - ) - } catch (e: Exception) { - throw Exception("Export failed: ${e.message}") - } - } - suspend fun exportAllDataToZipUri(context: Context, uri: android.net.Uri) { try { - // Collect all data with proper error handling + // Collect all data val allGyms = gymDao.getAllGyms().first() val allProblems = problemDao.getAllProblems().first() val allSessions = sessionDao.getAllSessions().first() @@ -138,14 +81,16 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) // Validate data integrity before export validateDataIntegrity(allGyms, allProblems, allSessions, allAttempts) - val exportData = - ClimbDataExport( + // Create backup data using platform-neutral format + val backupData = + ClimbDataBackup( exportedAt = LocalDateTime.now().toString(), version = "2.0", - gyms = allGyms, - problems = allProblems, - sessions = allSessions, - attempts = allAttempts + formatVersion = "2.0", + gyms = allGyms.map { BackupGym.fromGym(it) }, + problems = allProblems.map { BackupProblem.fromProblem(it) }, + sessions = allSessions.map { BackupClimbSession.fromClimbSession(it) }, + attempts = allAttempts.map { BackupAttempt.fromAttempt(it) } ) // Collect all referenced image paths and validate they exist @@ -160,7 +105,7 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) imagePath ) imageFile.exists() && imageFile.length() > 0 - } catch (e: Exception) { + } catch (_: Exception) { false } } @@ -169,7 +114,7 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) ZipExportImportUtils.createExportZipToUri( context = context, uri = uri, - exportData = exportData, + exportData = backupData, referencedImagePaths = validImagePaths ) } catch (e: Exception) { @@ -195,7 +140,7 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) // Parse and validate the data structure val importData = try { - json.decodeFromString(importResult.jsonContent) + json.decodeFromString(importResult.jsonContent) } catch (e: Exception) { throw Exception("Invalid data format: ${e.message}") } @@ -210,44 +155,47 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) gymDao.deleteAllGyms() // Import gyms first (problems depend on gyms) - importData.gyms.forEach { gym -> + importData.gyms.forEach { backupGym -> try { - gymDao.insertGym(gym) + gymDao.insertGym(backupGym.toGym()) } catch (e: Exception) { - throw Exception("Failed to import gym ${gym.name}: ${e.message}") + throw Exception("Failed to import gym '${backupGym.name}': ${e.message}") } } // Import problems with updated image paths - val updatedProblems = + val updatedBackupProblems = ZipExportImportUtils.updateProblemImagePaths( importData.problems, importResult.importedImagePaths ) - updatedProblems.forEach { problem -> + // Import problems (depends on gyms) + updatedBackupProblems.forEach { backupProblem -> try { - problemDao.insertProblem(problem) + problemDao.insertProblem(backupProblem.toProblem()) } catch (e: Exception) { - throw Exception("Failed to import problem ${problem.name}: ${e.message}") + throw Exception( + "Failed to import problem '${backupProblem.name}': ${e.message}" + ) } } // Import sessions - importData.sessions.forEach { session -> + importData.sessions.forEach { backupSession -> try { - sessionDao.insertSession(session) + sessionDao.insertSession(backupSession.toClimbSession()) } catch (e: Exception) { - throw Exception("Failed to import session: ${e.message}") + throw Exception("Failed to import session '${backupSession.id}': ${e.message}") } } // Import attempts last (depends on problems and sessions) - importData.attempts.forEach { attempt -> + importData.attempts.forEach { backupAttempt -> try { - attemptDao.insertAttempt(attempt) + attemptDao.insertAttempt(backupAttempt.toAttempt()) } catch (e: Exception) { - throw Exception("Failed to import attempt: ${e.message}") + throw Exception("Failed to import attempt '${backupAttempt.id}': ${e.message}") } } } catch (e: Exception) { @@ -291,7 +239,7 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) } } - private fun validateImportData(importData: ClimbDataExport) { + private fun validateImportData(importData: ClimbDataBackup) { if (importData.gyms.isEmpty()) { throw Exception("Import data is invalid: no gyms found") } @@ -339,13 +287,3 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) } } } - -@kotlinx.serialization.Serializable -data class ClimbDataExport( - val exportedAt: String, - val version: String = "2.0", - val gyms: List, - val problems: List, - val sessions: List, - val attempts: List -) diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/ZipExportImportUtils.kt b/android/app/src/main/java/com/atridad/openclimb/utils/ZipExportImportUtils.kt index 9bd349b..a8ee1a6 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/ZipExportImportUtils.kt +++ b/android/app/src/main/java/com/atridad/openclimb/utils/ZipExportImportUtils.kt @@ -1,7 +1,8 @@ package com.atridad.openclimb.utils import android.content.Context -import kotlinx.serialization.json.Json +import com.atridad.openclimb.data.format.BackupProblem +import com.atridad.openclimb.data.format.ClimbDataBackup import java.io.File import java.io.FileInputStream import java.io.FileOutputStream @@ -10,13 +11,15 @@ import java.time.LocalDateTime import java.util.zip.ZipEntry import java.util.zip.ZipInputStream import java.util.zip.ZipOutputStream +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json object ZipExportImportUtils { - + private const val DATA_JSON_FILENAME = "data.json" private const val IMAGES_DIR_NAME = "images" private const val METADATA_FILENAME = "metadata.txt" - + /** * Creates a ZIP file containing the JSON data and all referenced images * @param context Android context @@ -26,19 +29,26 @@ object ZipExportImportUtils { * @return The created ZIP file */ fun createExportZip( - context: Context, - exportData: com.atridad.openclimb.data.repository.ClimbDataExport, - referencedImagePaths: Set, - directory: File? = null + context: Context, + exportData: ClimbDataBackup, + referencedImagePaths: Set, + directory: File? = null ): File { - val exportDir = directory ?: File(context.getExternalFilesDir(android.os.Environment.DIRECTORY_DOCUMENTS), "OpenClimb") + val exportDir = + directory + ?: File( + context.getExternalFilesDir( + android.os.Environment.DIRECTORY_DOCUMENTS + ), + "OpenClimb" + ) if (!exportDir.exists()) { exportDir.mkdirs() } - + val timestamp = LocalDateTime.now().toString().replace(":", "-").replace(".", "-") val zipFile = File(exportDir, "openclimb_export_$timestamp.zip") - + try { ZipOutputStream(FileOutputStream(zipFile)).use { zipOut -> // Add metadata file first @@ -47,19 +57,19 @@ object ZipExportImportUtils { zipOut.putNextEntry(metadataEntry) zipOut.write(metadata.toByteArray()) zipOut.closeEntry() - + // Add JSON data file - val json = Json { - prettyPrint = true + val json = Json { + prettyPrint = true ignoreUnknownKeys = true } - val jsonString = json.encodeToString(com.atridad.openclimb.data.repository.ClimbDataExport.serializer(), exportData) - + val jsonString = json.encodeToString(exportData) + val jsonEntry = ZipEntry(DATA_JSON_FILENAME) zipOut.putNextEntry(jsonEntry) zipOut.write(jsonString.toByteArray()) zipOut.closeEntry() - + // Add images with validation var successfulImages = 0 referencedImagePaths.forEach { imagePath -> @@ -68,31 +78,39 @@ object ZipExportImportUtils { if (imageFile.exists() && imageFile.length() > 0) { val imageEntry = ZipEntry("$IMAGES_DIR_NAME/${imageFile.name}") zipOut.putNextEntry(imageEntry) - + FileInputStream(imageFile).use { imageInput -> imageInput.copyTo(zipOut) } zipOut.closeEntry() successfulImages++ } else { - android.util.Log.w("ZipExportImportUtils", "Image file not found or empty: $imagePath") + android.util.Log.w( + "ZipExportImportUtils", + "Image file not found or empty: $imagePath" + ) } } catch (e: Exception) { - android.util.Log.e("ZipExportImportUtils", "Failed to add image $imagePath: ${e.message}") + android.util.Log.e( + "ZipExportImportUtils", + "Failed to add image $imagePath: ${e.message}" + ) } } - + // Log export summary - android.util.Log.i("ZipExportImportUtils", "Export completed: ${successfulImages}/${referencedImagePaths.size} images included") + android.util.Log.i( + "ZipExportImportUtils", + "Export completed: ${successfulImages}/${referencedImagePaths.size} images included" + ) } - + // Validate the created ZIP file if (!zipFile.exists() || zipFile.length() == 0L) { throw IOException("Failed to create ZIP file: file is empty or doesn't exist") } - + return zipFile - } catch (e: Exception) { // Clean up failed export if (zipFile.exists()) { @@ -101,7 +119,7 @@ object ZipExportImportUtils { throw IOException("Failed to create export ZIP: ${e.message}") } } - + /** * Creates a ZIP file and writes it to a provided URI * @param context Android context @@ -110,10 +128,10 @@ object ZipExportImportUtils { * @param referencedImagePaths Set of image paths referenced in the data */ fun createExportZipToUri( - context: Context, - uri: android.net.Uri, - exportData: com.atridad.openclimb.data.repository.ClimbDataExport, - referencedImagePaths: Set + context: Context, + uri: android.net.Uri, + exportData: ClimbDataBackup, + referencedImagePaths: Set ) { try { context.contentResolver.openOutputStream(uri)?.use { outputStream -> @@ -124,19 +142,19 @@ object ZipExportImportUtils { zipOut.putNextEntry(metadataEntry) zipOut.write(metadata.toByteArray()) zipOut.closeEntry() - + // Add JSON data file - val json = Json { - prettyPrint = true + val json = Json { + prettyPrint = true ignoreUnknownKeys = true } - val jsonString = json.encodeToString(com.atridad.openclimb.data.repository.ClimbDataExport.serializer(), exportData) - + val jsonString = json.encodeToString(exportData) + val jsonEntry = ZipEntry(DATA_JSON_FILENAME) zipOut.putNextEntry(jsonEntry) zipOut.write(jsonString.toByteArray()) zipOut.closeEntry() - + // Add images with validation var successfulImages = 0 referencedImagePaths.forEach { imagePath -> @@ -145,7 +163,7 @@ object ZipExportImportUtils { if (imageFile.exists() && imageFile.length() > 0) { val imageEntry = ZipEntry("$IMAGES_DIR_NAME/${imageFile.name}") zipOut.putNextEntry(imageEntry) - + FileInputStream(imageFile).use { imageInput -> imageInput.copyTo(zipOut) } @@ -153,22 +171,28 @@ object ZipExportImportUtils { successfulImages++ } } catch (e: Exception) { - android.util.Log.e("ZipExportImportUtils", "Failed to add image $imagePath: ${e.message}") + android.util.Log.e( + "ZipExportImportUtils", + "Failed to add image $imagePath: ${e.message}" + ) } } - - android.util.Log.i("ZipExportImportUtils", "Export to URI completed: ${successfulImages}/${referencedImagePaths.size} images included") + + android.util.Log.i( + "ZipExportImportUtils", + "Export to URI completed: ${successfulImages}/${referencedImagePaths.size} images included" + ) } - } ?: throw IOException("Could not open output stream") - + } + ?: throw IOException("Could not open output stream") } catch (e: Exception) { throw IOException("Failed to create export ZIP to URI: ${e.message}") } } - + private fun createMetadata( - exportData: com.atridad.openclimb.data.repository.ClimbDataExport, - referencedImagePaths: Set + exportData: ClimbDataBackup, + referencedImagePaths: Set ): String { return buildString { appendLine("OpenClimb Export Metadata") @@ -183,15 +207,13 @@ object ZipExportImportUtils { appendLine("Format: ZIP with embedded JSON data and images") } } - - /** - * Data class to hold extraction results - */ + + /** Data class to hold extraction results */ data class ImportResult( - val jsonContent: String, - val importedImagePaths: Map // original filename -> new relative path + val jsonContent: String, + val importedImagePaths: Map // original filename -> new relative path ) - + /** * Extracts a ZIP file and returns the JSON content and imported image paths * @param context Android context @@ -200,106 +222,125 @@ object ZipExportImportUtils { */ fun extractImportZip(context: Context, zipFile: File): ImportResult { var jsonContent = "" - var metadataContent = "" val importedImagePaths = mutableMapOf() var foundRequiredFiles = mutableSetOf() - + try { ZipInputStream(FileInputStream(zipFile)).use { zipIn -> var entry = zipIn.nextEntry - + while (entry != null) { when { entry.name == METADATA_FILENAME -> { // Read metadata for validation - metadataContent = zipIn.readBytes().toString(Charsets.UTF_8) + val metadataContent = zipIn.readBytes().toString(Charsets.UTF_8) foundRequiredFiles.add("metadata") - android.util.Log.i("ZipExportImportUtils", "Found metadata: ${metadataContent.lines().take(3).joinToString()}") + android.util.Log.i( + "ZipExportImportUtils", + "Found metadata: ${metadataContent.lines().take(3).joinToString()}" + ) } - entry.name == DATA_JSON_FILENAME -> { // Read JSON data jsonContent = zipIn.readBytes().toString(Charsets.UTF_8) foundRequiredFiles.add("data") } - entry.name.startsWith("$IMAGES_DIR_NAME/") && !entry.isDirectory -> { // Extract image file val originalFilename = entry.name.substringAfter("$IMAGES_DIR_NAME/") - + try { // Create temporary file to hold the extracted image - val tempFile = File.createTempFile("import_image_", "_$originalFilename", context.cacheDir) - - FileOutputStream(tempFile).use { output -> - zipIn.copyTo(output) - } - + val tempFile = + File.createTempFile( + "import_image_", + "_$originalFilename", + context.cacheDir + ) + + FileOutputStream(tempFile).use { output -> zipIn.copyTo(output) } + // Validate the extracted image if (tempFile.exists() && tempFile.length() > 0) { // Import the image to permanent storage val newPath = ImageUtils.importImageFile(context, tempFile) if (newPath != null) { importedImagePaths[originalFilename] = newPath - android.util.Log.d("ZipExportImportUtils", "Successfully imported image: $originalFilename -> $newPath") + android.util.Log.d( + "ZipExportImportUtils", + "Successfully imported image: $originalFilename -> $newPath" + ) } else { - android.util.Log.w("ZipExportImportUtils", "Failed to import image: $originalFilename") + android.util.Log.w( + "ZipExportImportUtils", + "Failed to import image: $originalFilename" + ) } } else { - android.util.Log.w("ZipExportImportUtils", "Extracted image is empty: $originalFilename") + android.util.Log.w( + "ZipExportImportUtils", + "Extracted image is empty: $originalFilename" + ) } - + // Clean up temp file tempFile.delete() - } catch (e: Exception) { - android.util.Log.e("ZipExportImportUtils", "Failed to process image $originalFilename: ${e.message}") + android.util.Log.e( + "ZipExportImportUtils", + "Failed to process image $originalFilename: ${e.message}" + ) } } - else -> { - android.util.Log.d("ZipExportImportUtils", "Skipping ZIP entry: ${entry.name}") + android.util.Log.d( + "ZipExportImportUtils", + "Skipping ZIP entry: ${entry.name}" + ) } } - + zipIn.closeEntry() entry = zipIn.nextEntry } } - + // Validate that we found the required files if (!foundRequiredFiles.contains("data")) { throw IOException("Invalid ZIP file: data.json not found") } - + if (jsonContent.isBlank()) { throw IOException("Invalid ZIP file: data.json is empty") } - - android.util.Log.i("ZipExportImportUtils", "Import extraction completed: ${importedImagePaths.size} images processed") - + + android.util.Log.i( + "ZipExportImportUtils", + "Import extraction completed: ${importedImagePaths.size} images processed" + ) + return ImportResult(jsonContent, importedImagePaths) - } catch (e: Exception) { throw IOException("Failed to extract import ZIP: ${e.message}") } } /** - * Updates image paths in a problem list after import - * This function maps the old image paths to the new ones after import + * Updates image paths in a problem list after import This function maps the old image paths to + * the new ones after import */ fun updateProblemImagePaths( - problems: List, - imagePathMapping: Map - ): List { + problems: List, + imagePathMapping: Map + ): List { return problems.map { problem -> - val updatedImagePaths = problem.imagePaths.mapNotNull { oldPath -> - // Extract filename from the old path - val filename = oldPath.substringAfterLast("/") - imagePathMapping[filename] - } - problem.copy(imagePaths = updatedImagePaths) + val updatedImagePaths = + (problem.imagePaths ?: emptyList()).mapNotNull { oldPath -> + // Extract filename from the old path + val filename = oldPath.substringAfterLast("/") + imagePathMapping[filename] + } + problem.withUpdatedImagePaths(updatedImagePaths) } } } diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e708b1c023ec8b20f512888fe07c5bd3ff77bb8f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59203 zcma&O1CT9Y(k9%tZQHhO+qUh#ZQHhO+qmuS+qP|E@9xZO?0h@l{(r>DQ>P;GjjD{w zH}lENr;dU&FbEU?00aa80D$0M0RRB{U*7-#kbjS|qAG&4l5%47zyJ#WrfA#1$1Ctx zf&Z_d{GW=lf^w2#qRJ|CvSJUi(^E3iv~=^Z(zH}F)3Z%V3`@+rNB7gTVU{Bb~90p|f+0(v;nz01EG7yDMX9@S~__vVgv%rS$+?IH+oZ03D5zYrv|^ zC1J)SruYHmCki$jLBlTaE5&dFG9-kq3!^i>^UQL`%gn6)jz54$WDmeYdsBE9;PqZ_ zoGd=P4+|(-u4U1dbAVQrFWoNgNd;0nrghPFbQrJctO>nwDdI`Q^i0XJDUYm|T|RWc zZ3^Qgo_Qk$%Fvjj-G}1NB#ZJqIkh;kX%V{THPqOyiq)d)0+(r9o(qKlSp*hmK#iIY zA^)Vr$-Hz<#SF=0@tL@;dCQsm`V9s1vYNq}K1B)!XSK?=I1)tX+bUV52$YQu*0%fnWEukW>mxkz+%3-S!oguE8u#MGzST8_Dy^#U?fA@S#K$S@9msUiX!gd_ow>08w5)nX{-KxqMOo7d?k2&?Vf z&diGDtZr(0cwPe9z9FAUSD9KC)7(n^lMWuayCfxzy8EZsns%OEblHFSzP=cL6}?J| z0U$H!4S_TVjj<`6dy^2j`V`)mC;cB%* z8{>_%E1^FH!*{>4a7*C1v>~1*@TMcLK{7nEQ!_igZC}ikJ$*<$yHy>7)oy79A~#xE zWavoJOIOC$5b6*q*F_qN1>2#MY)AXVyr$6x4b=$x^*aqF*L?vmj>Mgv+|ITnw_BoW zO?jwHvNy^prH{9$rrik1#fhyU^MpFqF2fYEt(;4`Q&XWOGDH8k6M=%@fics4ajI;st# zCU^r1CK&|jzUhRMv;+W~6N;u<;#DI6cCw-otsc@IsN3MoSD^O`eNflIoR~l4*&-%RBYk@gb^|-JXs&~KuSEmMxB}xSb z@K76cXD=Y|=I&SNC2E+>Zg?R6E%DGCH5J1nU!A|@eX9oS(WPaMm==k2s_ueCqdZw| z&hqHp)47`c{BgwgvY2{xz%OIkY1xDwkw!<0veB#yF4ZKJyabhyyVS`gZepcFIk%e2 zTcrmt2@-8`7i-@5Nz>oQWFuMC_KlroCl(PLSodswHqJ3fn<;gxg9=}~3x_L3P`9Sn zChIf}8vCHvTriz~T2~FamRi?rh?>3bX1j}%bLH+uFX+p&+^aXbOK7clZxdU~6Uxgy z8R=obwO4dL%pmVo*Ktf=lH6hnlz_5k3cG;m8lgaPp~?eD!Yn2kf)tU6PF{kLyn|oI@eQ`F z3IF7~Blqg8-uwUuWZScRKn%c2_}dXB6Dx_&xR*n9M9LXasJhtZdr$vBY!rP{c@=)& z#!?L$2UrkvClwQO>U*fSMs67oSj2mxiJ$t;E|>q%Kh_GzzWWO&3;ufU%2z%ucBU8H z3WIwr$n)cfCXR&>tyB7BcSInK>=ByZA%;cVEJhcg<#6N{aZC4>K41XF>ZgjG`z_u& zGY?;Ad?-sgiOnI`oppF1o1Gurqbi*;#x2>+SSV6|1^G@ooVy@fg?wyf@0Y!UZ4!}nGuLeC^l)6pwkh|oRY`s1Pm$>zZ3u-83T|9 zGaKJIV3_x+u1>cRibsaJpJqhcm%?0-L;2 zitBrdRxNmb0OO2J%Y&Ym(6*`_P3&&5Bw157{o7LFguvxC$4&zTy#U=W*l&(Q2MNO} zfaUwYm{XtILD$3864IA_nn34oVa_g^FRuHL5wdUd)+W-p-iWCKe8m_cMHk+=? zeKX)M?Dt(|{r5t7IenkAXo%&EXIb-i^w+0CX0D=xApC=|Xy(`xy+QG^UyFe z+#J6h_&T5i#sV)hj3D4WN%z;2+jJcZxcI3*CHXGmOF3^)JD5j&wfX)e?-|V0GPuA+ zQFot%aEqGNJJHn$!_}#PaAvQ^{3-Ye7b}rWwrUmX53(|~i0v{}G_sI9uDch_brX&6 zWl5Ndj-AYg(W9CGfQf<6!YmY>Ey)+uYd_JNXH=>|`OH-CDCmcH(0%iD_aLlNHKH z7bcW-^5+QV$jK?R*)wZ>r9t}loM@XN&M-Pw=F#xn(;u3!(3SXXY^@=aoj70;_=QE9 zGghsG3ekq#N||u{4We_25U=y#T*S{4I{++Ku)> zQ!DZW;pVcn>b;&g2;YE#+V`v*Bl&Y-i@X6D*OpNA{G@JAXho&aOk(_j^weW{#3X5Y z%$q_wpb07EYPdmyH(1^09i$ca{O<}7) zRWncXdSPgBE%BM#by!E>tdnc$8RwUJg1*x($6$}ae$e9Knj8gvVZe#bLi!<+&BkFj zg@nOpDneyc+hU9P-;jmOSMN|*H#>^Ez#?;%C3hg_65leSUm;iz)UkW)jX#p)e&S&M z1|a?wDzV5NVnlhRBCd_;F87wp>6c<&nkgvC+!@KGiIqWY4l}=&1w7|r6{oBN8xyzh zG$b#2=RJp_iq6)#t5%yLkKx(0@D=C3w+oiXtSuaQ%I1WIb-eiE$d~!)b@|4XLy!CZ z9p=t=%3ad@Ep+<9003D2KZ5VyP~_n$=;~r&YUg5UZ0KVD&tR1DHy9x)qWtKJp#Kq# zP*8p#W(8JJ_*h_3W}FlvRam?<4Z+-H77^$Lvi+#vmhL9J zJ<1SV45xi;SrO2f=-OB(7#iNA5)x1uNC-yNxUw|!00vcW2PufRm>e~toH;M0Q85MQLWd?3O{i8H+5VkR@l9Dg-ma ze2fZ%>G(u5(k9EHj2L6!;(KZ8%8|*-1V|B#EagbF(rc+5iL_5;Eu)L4Z-V;0HfK4d z*{utLse_rvHZeQ>V5H=f78M3Ntg1BPxFCVD{HbNA6?9*^YIq;B-DJd{Ca2L#)qWP? zvX^NhFmX?CTWw&Ns}lgs;r3i+Bq@y}Ul+U%pzOS0Fcv9~aB(0!>GT0)NO?p=25LjN z2bh>6RhgqD7bQj#k-KOm@JLgMa6>%-ok1WpOe)FS^XOU{c?d5shG(lIn3GiVBxmg`u%-j=)^v&pX1JecJics3&jvPI)mDut52? z3jEA)DM%}BYbxxKrizVYwq?(P&19EXlwD9^-6J+4!}9{ywR9Gk42jjAURAF&EO|~N z)?s>$Da@ikI4|^z0e{r`J8zIs>SpM~Vn^{3fArRu;?+43>lD+^XtUcY1HidJwnR6+ z!;oG2=B6Z_=M%*{z-RaHc(n|1RTKQdNjjV!Pn9lFt^4w|AeN06*j}ZyhqZ^!-=cyGP_ShV1rGxkx8t zB;8`h!S{LD%ot``700d0@Grql(DTt4Awgmi+Yr0@#jbe=2#UkK%rv=OLqF)9D7D1j z!~McAwMYkeaL$~kI~90)5vBhBzWYc3Cj1WI0RS`z000R8-@ET0dA~*r(gSiCJmQMN&4%1D zyVNf0?}sBH8zNbBLn>~(W{d3%@kL_eQ6jEcR{l>C|JK z(R-fA!z|TTRG40|zv}7E@PqCAXP3n`;%|SCQ|ZS%ym$I{`}t3KPL&^l5`3>yah4*6 zifO#{VNz3)?ZL$be;NEaAk9b#{tV?V7 zP|wf5YA*1;s<)9A4~l3BHzG&HH`1xNr#%){4xZ!jq%o=7nN*wMuXlFV{HaiQLJ`5G zBhDi#D(m`Q1pLh@Tq+L;OwuC52RdW7b8}~60WCOK5iYMUad9}7aWBuILb({5=z~YF zt?*Jr5NG+WadM{mDL>GyiByCuR)hd zA=HM?J6l1Xv0Dl+LW@w$OTcEoOda^nFCw*Sy^I@$sSuneMl{4ys)|RY#9&NxW4S)9 zq|%83IpslTLoz~&vTo!Ga@?rj_kw{|k{nv+w&Ku?fyk4Ki4I?);M|5Axm)t+BaE)D zm(`AQ#k^DWrjbuXoJf2{Aj^KT zFb1zMSqxq|vceV+Mf-)$oPflsO$@*A0n0Z!R{&(xh8s}=;t(lIy zv$S8x>m;vQNHuRzoaOo?eiWFe{0;$s`Bc+Osz~}Van${u;g(su`3lJ^TEfo~nERfP z)?aFzpDgnLYiERsKPu|0tq4l2wT)Atr6Qb%m-AUn6HnCue*yWICp7TjW$@sO zm5rm4aTcPQ(rfi7a`xP7cKCFrJD}*&_~xgLyr^-bmsL}y;A5P|al8J3WUoBSjqu%v zxC;mK!g(7r6RRJ852Z~feoC&sD3(6}^5-uLK8o)9{8L_%%rItZK9C){UxB|;G>JbP zsRRtS4-3B*5c+K2kvmgZK8472%l>3cntWUOVHxB|{Ay~aOg5RN;{PJgeVD*H%ac+y!h#wi%o2bF2Ca8IyMyH{>4#{E_8u^@+l-+n=V}Sq?$O z{091@v%Bd*3pk0^2UtiF9Z+(a@wy6 zUdw8J*ze$K#=$48IBi1U%;hmhO>lu!uU;+RS}p&6@rQila7WftH->*A4=5W|Fmtze z)7E}jh@cbmr9iup^i%*(uF%LG&!+Fyl@LFA-}Ca#bxRfDJAiR2dt6644TaYw1Ma79 zt8&DYj31j^5WPNf5P&{)J?WlCe@<3u^78wnd(Ja4^a>{^Tw}W>|Cjt^If|7l^l)^Q zbz|7~CF(k_9~n|h;ysZ+jHzkXf(*O*@5m zLzUmbHp=x!Q|!9NVXyipZ3)^GuIG$k;D)EK!a5=8MFLI_lpf`HPKl=-Ww%z8H_0$j ztJ||IfFG1lE9nmQ0+jPQy zCBdKkjArH@K7jVcMNz);Q(Q^R{d5G?-kk;Uu_IXSyWB)~KGIizZL(^&qF;|1PI7!E zTP`%l)gpX|OFn&)M%txpQ2F!hdA~hX1Cm5)IrdljqzRg!f{mN%G~H1&oqe`5eJCIF zHdD7O;AX-{XEV(a`gBFJ9ews#CVS2y!&>Cm_dm3C8*n3MA*e67(WC?uP@8TXuMroq z{#w$%z@CBIkRM7?}Xib+>hRjy?%G!fiw8! z8(gB+8J~KOU}yO7UGm&1g_MDJ$IXS!`+*b*QW2x)9>K~Y*E&bYMnjl6h!{17_8d!%&9D`a7r&LKZjC<&XOvTRaKJ1 zUY@hl5^R&kZl3lU3njk`3dPzxj$2foOL26r(9zsVF3n_F#v)s5vv3@dgs|lP#eylq62{<-vczqP!RpVBTgI>@O6&sU>W|do17+#OzQ7o5A$ICH z?GqwqnK^n2%LR;$^oZM;)+>$X3s2n}2jZ7CdWIW0lnGK-b#EG01)P@aU`pg}th&J-TrU`tIpb5t((0eu|!u zQz+3ZiOQ^?RxxK4;zs=l8q!-n7X{@jSwK(iqNFiRColuEOg}!7cyZi`iBX4g1pNBj zAPzL?P^Ljhn;1$r8?bc=#n|Ed7wB&oHcw()&*k#SS#h}jO?ZB246EGItsz*;^&tzp zu^YJ0=lwsi`eP_pU8}6JA7MS;9pfD;DsSsLo~ogzMNP70@@;Fm8f0^;>$Z>~}GWRw!W5J3tNX*^2+1f3hz{~rIzJo z6W%J(H!g-eI_J1>0juX$X4Cl6i+3wbc~k146UIX&G22}WE>0ga#WLsn9tY(&29zBvH1$`iWtTe zG2jYl@P!P)eb<5DsR72BdI7-zP&cZNI{7q3e@?N8IKc4DE#UVr->|-ryuJXk^u^>4 z$3wE~=q390;XuOQP~TNoDR?#|NSPJ%sTMInA6*rJ%go|=YjGe!B>z6u$IhgQSwoV* zjy3F2#I>uK{42{&IqP59)Y(1*Z>>#W8rCf4_eVsH)`v!P#^;BgzKDR`ARGEZzkNX+ zJUQu=*-ol=Xqqt5=`=pA@BIn@6a9G8C{c&`i^(i+BxQO9?YZ3iu%$$da&Kb?2kCCo zo7t$UpSFWqmydXf@l3bVJ=%K?SSw)|?srhJ-1ZdFu*5QhL$~-IQS!K1s@XzAtv6*Y zl8@(5BlWYLt1yAWy?rMD&bwze8bC3-GfNH=p zynNFCdxyX?K&G(ZZ)afguQ2|r;XoV^=^(;Cku#qYn4Lus`UeKt6rAlFo_rU`|Rq z&G?~iWMBio<78of-2X(ZYHx~=U0Vz4btyXkctMKdc9UM!vYr~B-(>)(Hc|D zMzkN4!PBg%tZoh+=Gba!0++d193gbMk2&krfDgcbx0jI92cq?FFESVg0D$>F+bil} zY~$)|>1HZsX=5sAZ2WgPB5P=8X#TI+NQ(M~GqyVB53c6IdX=k>Wu@A0Svf5#?uHaF zsYn|koIi3$(%GZ2+G+7Fv^lHTb#5b8sAHSTnL^qWZLM<(1|9|QFw9pnRU{svj}_Al zL)b9>fN{QiA($8peNEJyy`(a{&uh-T4_kdZFIVsKKVM(?05}76EEz?#W za^fiZOAd14IJ4zLX-n7Lq0qlQ^lW8Cvz4UKkV9~P}>sq0?xD3vg+$4vLm~C(+ zM{-3Z#qnZ09bJ>}j?6ry^h+@PfaD7*jZxBEY4)UG&daWb??6)TP+|3#Z&?GL?1i+280CFsE|vIXQbm| zM}Pk!U`U5NsNbyKzkrul-DzwB{X?n3E6?TUHr{M&+R*2%yOiXdW-_2Yd6?38M9Vy^ z*lE%gA{wwoSR~vN0=no}tP2Ul5Gk5M(Xq`$nw#ndFk`tcpd5A=Idue`XZ!FS>Q zG^0w#>P4pPG+*NC9gLP4x2m=cKP}YuS!l^?sHSFftZy{4CoQrb_ z^20(NnG`wAhMI=eq)SsIE~&Gp9Ne0nD4%Xiu|0Fj1UFk?6avDqjdXz{O1nKao*46y zT8~iA%Exu=G#{x=KD;_C&M+Zx4+n`sHT>^>=-1YM;H<72k>$py1?F3#T1*ef9mLZw z5naLQr?n7K;2l+{_uIw*_1nsTn~I|kkCgrn;|G~##hM;9l7Jy$yJfmk+&}W@JeKcF zx@@Woiz8qdi|D%aH3XTx5*wDlbs?dC1_nrFpm^QbG@wM=i2?Zg;$VK!c^Dp8<}BTI zyRhAq@#%2pGV49*Y5_mV4+OICP|%I(dQ7x=6Ob}>EjnB_-_18*xrY?b%-yEDT(wrO z9RY2QT0`_OpGfMObKHV;QLVnrK%mc?$WAdIT`kJQT^n%GuzE7|9@k3ci5fYOh(287 zuIbg!GB3xLg$YN=n)^pHGB0jH+_iIiC=nUcD;G6LuJsjn2VI1cyZx=a?ShCsF==QK z;q~*m&}L<-cb+mDDXzvvrRsybcgQ;Vg21P(uLv5I+eGc7o7tc6`;OA9{soHFOz zT~2?>Ts}gprIX$wRBb4yE>ot<8+*Bv`qbSDv*VtRi|cyWS>)Fjs>fkNOH-+PX&4(~ z&)T8Zam2L6puQl?;5zg9h<}k4#|yH9czHw;1jw-pwBM*O2hUR6yvHATrI%^mvs9q_ z&ccT0>f#eDG<^WG^q@oVqlJrhxH)dcq2cty@l3~|5#UDdExyXUmLQ}f4#;6fI{f^t zDCsgIJ~0`af%YR%Ma5VQq-p21k`vaBu6WE?66+5=XUd%Ay%D$irN>5LhluRWt7 zov-=f>QbMk*G##&DTQyou$s7UqjjW@k6=!I@!k+S{pP8R(2=e@io;N8E`EOB;OGoI zw6Q+{X1_I{OO0HPpBz!X!@`5YQ2)t{+!?M_iH25X(d~-Zx~cXnS9z>u?+If|iNJbx zyFU2d1!ITX64D|lE0Z{dLRqL1Ajj=CCMfC4lD3&mYR_R_VZ>_7_~|<^o*%_&jevU+ zQ4|qzci=0}Jydw|LXLCrOl1_P6Xf@c0$ieK2^7@A9UbF{@V_0p%lqW|L?5k>bVM8|p5v&2g;~r>B8uo<4N+`B zH{J)h;SYiIVx@#jI&p-v3dwL5QNV1oxPr8J%ooezTnLW>i*3Isb49%5i!&ac_dEXv zvXmVUck^QHmyrF8>CGXijC_R-y(Qr{3Zt~EmW)-nC!tiH`wlw5D*W7Pip;T?&j%kX z6DkZX4&}iw>hE(boLyjOoupf6JpvBG8}jIh!!VhnD0>}KSMMo{1#uU6kiFcA04~|7 zVO8eI&x1`g4CZ<2cYUI(n#wz2MtVFHx47yE5eL~8bot~>EHbevSt}LLMQX?odD{Ux zJMnam{d)W4da{l7&y-JrgiU~qY3$~}_F#G7|MxT)e;G{U`In&?`j<5D->}cb{}{T(4DF0BOk-=1195KB-E*o@c?`>y#4=dMtYtSY=&L{!TAjFVcq0y@AH`vH! z$41+u!Ld&}F^COPgL(EE{0X7LY&%D7-(?!kjFF7=qw<;`V{nwWBq<)1QiGJgUc^Vz ztMUlq1bZqKn17|6x6iAHbWc~l1HcmAxr%$Puv!znW)!JiukwIrqQ00|H$Z)OmGG@= zv%A8*4cq}(?qn4rN6o`$Y))(MyXr8R<2S^J+v(wmFmtac!%VOfN?&(8Nr!T@kV`N; z*Q33V3t`^rN&aBiHet)18wy{*wi1=W!B%B-Q6}SCrUl$~Hl{@!95ydml@FK8P=u4s z4e*7gV2s=YxEvskw2Ju!2%{8h01rx-3`NCPc(O zH&J0VH5etNB2KY6k4R@2Wvl^Ck$MoR3=)|SEclT2ccJ!RI9Nuter7u9@;sWf-%um;GfI!=eEIQ2l2p_YWUd{|6EG ze{yO6;lMc>;2tPrsNdi@&1K6(1;|$xe8vLgiouj%QD%gYk`4p{Ktv9|j+!OF-P?@p z;}SV|oIK)iwlBs+`ROXkhd&NK zzo__r!B>tOXpBJMDcv!Mq54P+n4(@dijL^EpO1wdg~q+!DT3lB<>9AANSe!T1XgC=J^)IP0XEZ()_vpu!!3HQyJhwh?r`Ae%Yr~b% zO*NY9t9#qWa@GCPYOF9aron7thfWT`eujS4`t2uG6)~JRTI;f(ZuoRQwjZjp5Pg34 z)rp$)Kr?R+KdJ;IO;pM{$6|2y=k_siqvp%)2||cHTe|b5Ht8&A{wazGNca zX$Ol?H)E_R@SDi~4{d-|8nGFhZPW;Cts1;08TwUvLLv&_2$O6Vt=M)X;g%HUr$&06 zISZb(6)Q3%?;3r~*3~USIg=HcJhFtHhIV(siOwV&QkQe#J%H9&E21!C*d@ln3E@J* zVqRO^<)V^ky-R|%{(9`l-(JXq9J)1r$`uQ8a}$vr9E^nNiI*thK8=&UZ0dsFN_eSl z(q~lnD?EymWLsNa3|1{CRPW60>DSkY9YQ;$4o3W7Ms&@&lv9eH!tk~N&dhqX&>K@} zi1g~GqglxkZ5pEFkllJ)Ta1I^c&Bt6#r(QLQ02yHTaJB~- zCcE=5tmi`UA>@P=1LBfBiqk)HB4t8D?02;9eXj~kVPwv?m{5&!&TFYhu>3=_ zsGmYZ^mo*-j69-42y&Jj0cBLLEulNRZ9vXE)8~mt9C#;tZs;=#M=1*hebkS;7(aGf zcs7zH(I8Eui9UU4L--))yy`&d&$In&VA2?DAEss4LAPCLd>-$i?lpXvn!gu^JJ$(DoUlc6wE98VLZ*z`QGQov5l4Fm_h?V-;mHLYDVOwKz7>e4+%AzeO>P6v}ndPW| zM>m#6Tnp7K?0mbK=>gV}=@k*0Mr_PVAgGMu$j+pWxzq4MAa&jpCDU&-5eH27Iz>m^ zax1?*HhG%pJ((tkR(V(O(L%7v7L%!_X->IjS3H5kuXQT2!ow(;%FDE>16&3r){!ex zhf==oJ!}YU89C9@mfDq!P3S4yx$aGB?rbtVH?sHpg?J5C->!_FHM%Hl3#D4eplxzQ zRA+<@LD%LKSkTk2NyWCg7u=$%F#;SIL44~S_OGR}JqX}X+=bc@swpiClB`Zbz|f!4 z7Ysah7OkR8liXfI`}IIwtEoL}(URrGe;IM8%{>b1SsqXh)~w}P>yiFRaE>}rEnNkT z!HXZUtxUp1NmFm)Dm@-{FI^aRQqpSkz}ZSyKR%Y}YHNzBk)ZIp} zMtS=aMvkgWKm9&oTcU0?S|L~CDqA+sHpOxwnswF-fEG)cXCzUR?ps@tZa$=O)=L+5 zf%m58cq8g_o}3?Bhh+c!w4(7AjxwQ3>WnVi<{{38g7yFboo>q|+7qs<$8CPXUFAN< zG&}BHbbyQ5n|qqSr?U~GY{@GJ{(Jny{bMaOG{|IkUj7tj^9pa9|FB_<+KHLxSxR;@ zHpS$4V)PP+tx}22fWx(Ku9y+}Ap;VZqD0AZW4gCDTPCG=zgJmF{|x;(rvdM|2|9a}cex6xrMkERnkE;}jvU-kmzd%_J50$M`lIPCKf+^*zL=@LW`1SaEc%=m zQ+lT06Gw+wVwvQ9fZ~#qd430v2HndFsBa9WjD0P}K(rZYdAt^5WQIvb%D^Q|pkVE^ zte$&#~zmULFACGfS#g=2OLOnIf2Of-k!(BIHjs77nr!5Q1*I9 z1%?=~#Oss!rV~?-6Gm~BWJiA4mJ5TY&iPm_$)H1_rTltuU1F3I(qTQ^U$S>%$l z)Wx1}R?ij0idp@8w-p!Oz{&*W;v*IA;JFHA9%nUvVDy7Q8woheC#|8QuDZb-L_5@R zOqHwrh|mVL9b=+$nJxM`3eE{O$sCt$UK^2@L$R(r^-_+z?lOo+me-VW=Zw z-Bn>$4ovfWd%SPY`ab-u9{INc*k2h+yH%toDHIyqQ zO68=u`N}RIIs7lsn1D){)~%>ByF<>i@qFb<-axvu(Z+6t7v<^z&gm9McRB~BIaDn$ z#xSGT!rzgad8o>~kyj#h1?7g96tOcCJniQ+*#=b7wPio>|6a1Z?_(TS{)KrPe}(8j z!#&A=k(&Pj^F;r)CI=Z{LVu>uj!_W1q4b`N1}E(i%;BWjbEcnD=mv$FL$l?zS6bW!{$7j1GR5ocn94P2u{ z70tAAcpqtQo<@cXw~@i-@6B23;317|l~S>CB?hR5qJ%J3EFgyBdJd^fHZu7AzHF(BQ!tyAz^L0`X z23S4Fe{2X$W0$zu9gm%rg~A>ijaE#GlYlrF9$ds^QtaszE#4M(OLVP2O-;XdT(XIC zatwzF*)1c+t~c{L=fMG8Z=k5lv>U0;C{caN1NItnuSMp)6G3mbahu>E#sj&oy94KC zpH}8oEw{G@N3pvHhp{^-YaZeH;K+T_1AUv;IKD<=mv^&Ueegrb!yf`4VlRl$M?wsl zZyFol(2|_QM`e_2lYSABpKR{{NlxlDSYQNkS;J66aT#MSiTx~;tUmvs-b*CrR4w=f z8+0;*th6kfZ3|5!Icx3RV11sp=?`0Jy3Fs0N4GZQMN=8HmT6%x9@{Dza)k}UwL6JT zHRDh;%!XwXr6yuuy`4;Xsn0zlR$k%r%9abS1;_v?`HX_hI|+EibVnlyE@3aL5vhQq zlIG?tN^w@0(v9M*&L+{_+RQZw=o|&BRPGB>e5=ys7H`nc8nx)|-g;s7mRc7hg{GJC zAe^vCIJhajmm7C6g! zL&!WAQ~5d_5)00?w_*|*H>3$loHrvFbitw#WvLB!JASO?#5Ig5$Ys10n>e4|3d;tS zELJ0|R4n3Az(Fl3-r^QiV_C;)lQ1_CW{5bKS15U|E9?ZgLec@%kXr84>5jV2a5v=w z?pB1GPdxD$IQL4)G||B_lI+A=08MUFFR4MxfGOu07vfIm+j=z9tp~5i_6jb`tR>qV z$#`=BQ*jpCjm$F0+F)L%xRlnS%#&gro6PiRfu^l!EVan|r3y}AHJQOORGx4~ z&<)3=K-tx518DZyp%|!EqpU!+X3Et7n2AaC5(AtrkW>_57i}$eqs$rupubg0a1+WO zGHZKLN2L0D;ab%{_S1Plm|hx8R?O14*w*f&2&bB050n!R2by zw!@XOQx$SqZ5I<(Qu$V6g>o#A!JVwErWv#(Pjx=KeS0@hxr4?13zj#oWwPS(7Ro|v z>Mp@Kmxo79q|}!5qtX2-O@U&&@6s~!I&)1WQIl?lTnh6UdKT_1R640S4~f=_xoN3- zI+O)$R@RjV$F=>Ti7BlnG1-cFKCC(t|Qjm{SalS~V-tX#+2ekRhwmN zZr`8{QF6y~Z!D|{=1*2D-JUa<(1Z=;!Ei!KiRNH?o{p5o3crFF=_pX9O-YyJchr$~ zRC`+G+8kx~fD2k*ZIiiIGR<8r&M@3H?%JVOfE>)})7ScOd&?OjgAGT@WVNSCZ8N(p zuQG~76GE3%(%h1*vUXg$vH{ua0b`sQ4f0*y=u~lgyb^!#CcPJa2mkSEHGLsnO^kb$ zru5_l#nu=Y{rSMWiYx?nO{8I!gH+?wEj~UM?IrG}E|bRIBUM>UlY<`T1EHpRr36vv zBi&dG8oxS|J$!zoaq{+JpJy+O^W(nt*|#g32bd&K^w-t>!Vu9N!k9eA8r!Xc{utY> zg9aZ(D2E0gL#W0MdjwES-7~Wa8iubPrd?8-$C4BP?*wok&O8+ykOx{P=Izx+G~hM8 z*9?BYz!T8~dzcZr#ux8kS7u7r@A#DogBH8km8Ry4slyie^n|GrTbO|cLhpqgMdsjX zJ_LdmM#I&4LqqsOUIXK8gW;V0B(7^$y#h3h>J0k^WJfAMeYek%Y-Dcb_+0zPJez!GM zAmJ1u;*rK=FNM0Nf}Y!!P9c4)HIkMnq^b;JFd!S3?_Qi2G#LIQ)TF|iHl~WKK6JmK zbv7rPE6VkYr_%_BT}CK8h=?%pk@3cz(UrZ{@h40%XgThP*-Oeo`T0eq9 zA8BnWZKzCy5e&&_GEsU4*;_k}(8l_&al5K-V*BFM=O~;MgRkYsOs%9eOY6s6AtE*<7GQAR2ulC3RAJrG_P1iQK5Z~&B z&f8X<>yJV6)oDGIlS$Y*D^Rj(cszTy5c81a5IwBr`BtnC6_e`ArI8CaTX_%rx7;cn zR-0?J_LFg*?(#n~G8cXut(1nVF0Oka$A$1FGcERU<^ggx;p@CZc?3UB41RY+wLS`LWFNSs~YP zuw1@DNN3lTd|jDL7gjBsd9}wIw}4xT2+8dBQzI00m<@?c2L%>}QLfK5%r!a-iII`p zX@`VEUH)uj^$;7jVUYdADQ2k*!1O3WdfgF?OMtUXNpQ1}QINamBTKDuv19^{$`8A1 zeq%q*O0mi@(%sZU>Xdb0Ru96CFqk9-L3pzLVsMQ`Xpa~N6CR{9Rm2)A|CI21L(%GW zh&)Y$BNHa=FD+=mBw3{qTgw)j0b!Eahs!rZnpu)z!!E$*eXE~##yaXz`KE5(nQM`s zD!$vW9XH)iMxu9R>r$VlLk9oIR%HxpUiW=BK@4U)|1WNQ=mz9a z^!KkO=>GaJ!GBXm{KJj^;kh-MkUlEQ%lza`-G&}C5y1>La1sR6hT=d*NeCnuK%_LV zOXt$}iP6(YJKc9j-Fxq~*ItVUqljQ8?oaysB-EYtFQp9oxZ|5m0^Hq(qV!S+hq#g( z?|i*H2MIr^Kxgz+3vIljQ*Feejy6S4v~jKEPTF~Qhq!(ms5>NGtRgO5vfPPc4Z^AM zTj!`5xEreIN)vaNxa|q6qWdg>+T`Ol0Uz)ckXBXEGvPNEL3R8hB3=C5`@=SYgAju1 z!)UBr{2~=~xa{b8>x2@C7weRAEuatC)3pkRhT#pMPTpSbA|tan%U7NGMvzmF?c!V8 z=pEWxbdXbTAGtWTyI?Fml%lEr-^AE}w#l(<7OIw;ctw}imYax&vR4UYNJZK6P7ZOd zP87XfhnUHxCUHhM@b*NbTi#(-8|wcv%3BGNs#zRCVV(W?1Qj6^PPQa<{yaBwZ`+<`w|;rqUY_C z&AeyKwwf*q#OW-F()lir=T^<^wjK65Lif$puuU5+tk$;e_EJ;Lu+pH>=-8=PDhkBg z8cWt%@$Sc#C6F$Vd+0507;{OOyT7Hs%nKS88q-W!$f~9*WGBpHGgNp}=C*7!RiZ5s zn1L_DbKF@B8kwhDiLKRB@lsXVVLK|ph=w%_`#owlf@s@V(pa`GY$8h%;-#h@TsO|Y8V=n@*!Rog7<7Cid%apR|x zOjhHCyfbIt%+*PCveTEcuiDi%Wx;O;+K=W?OFUV%)%~6;gl?<0%)?snDDqIvkHF{ zyI02)+lI9ov42^hL>ZRrh*HhjF9B$A@=H94iaBESBF=eC_KT$8A@uB^6$~o?3Wm5t1OIaqF^~><2?4e3c&)@wKn9bD? zoeCs;H>b8DL^F&>Xw-xjZEUFFTv>JD^O#1E#)CMBaG4DX9bD(Wtc8Rzq}9soQ8`jf zeSnHOL}<+WVSKp4kkq&?SbETjq6yr@4%SAqOG=9E(3YeLG9dtV+8vmzq+6PFPk{L; z(&d++iu=^F%b+ea$i2UeTC{R*0Isk;vFK!no<;L+(`y`3&H-~VTdKROkdyowo1iqR zbVW(3`+(PQ2>TKY>N!jGmGo7oeoB8O|P_!Ic@ zZ^;3dnuXo;WJ?S+)%P>{Hcg!Jz#2SI(s&dY4QAy_vRlmOh)QHvs_7c&zkJCmJGVvV zX;Mtb>QE+xp`KyciG$Cn*0?AK%-a|=o!+7x&&yzHQOS>8=B*R=niSnta^Pxp1`=md z#;$pS$4WCT?mbiCYU?FcHGZ#)kHVJTTBt^%XE(Q};aaO=Zik0UgLcc0I(tUpt(>|& zcxB_|fxCF7>&~5eJ=Dpn&5Aj{A^cV^^}(7w#p;HG&Q)EaN~~EqrE1qKrMAc&WXIE;>@<&)5;gD2?={Xf@Mvn@OJKw=8Mgn z!JUFMwD+s==JpjhroT&d{$kQAy%+d`a*XxDEVxy3`NHzmITrE`o!;5ClXNPb4t*8P zzAivdr{j_v!=9!^?T3y?gzmqDWX6mkzhIzJ-3S{T5bcCFMr&RPDryMcdwbBuZbsgN zGrp@^i?rcfN7v0NKGzDPGE#4yszxu=I_`MI%Z|10nFjU-UjQXXA?k8Pk|OE<(?ae) zE%vG#eZAlj*E7_3dx#Zz4kMLj>H^;}33UAankJiDy5ZvEhrjr`!9eMD8COp}U*hP+ zF}KIYx@pkccIgyxFm#LNw~G&`;o&5)2`5aogs`1~7cMZQ7zj!%L4E`2yzlQN6REX20&O<9 zKV6fyr)TScJPPzNTC2gL+0x#=u>(({{D7j)c-%tvqls3#Y?Z1m zV5WUE)zdJ{$p>yX;^P!UcXP?UD~YM;IRa#Rs5~l+*$&nO(;Ers`G=0D!twR(0GF@c zHl9E5DQI}Oz74n zfKP>&$q0($T4y$6w(p=ERAFh+>n%iaeRA%!T%<^+pg?M)@ucY<&59$x9M#n+V&>}=nO9wCV{O~lg&v#+jcUj(tQ z`0u1YH)-`U$15a{pBkGyPL0THv1P|4e@pf@3IBZS4dVJPo#H>pWq%Lr0YS-SeWash z8R7=jb28KPMI|_lo#GEO|5B?N_e``H*23{~a!AmUJ+fb4HX-%QI@lSEUxKlGV7z7Q zSKw@-TR>@1RL%w{x}dW#k1NgW+q4yt2Xf1J62Bx*O^WG8OJ|FqI4&@d3_o8Id@*)4 zYrk=>@!wv~mh7YWv*bZhxqSmFh2Xq)o=m;%n$I?GSz49l1$xRpPu_^N(vZ>*>Z<04 z2+rP70oM=NDysd!@fQdM2OcyT?3T^Eb@lIC-UG=Bw{BjQ&P`KCv$AcJ;?`vdZ4){d z&gkoUK{$!$$K`3*O-jyM1~p-7T*qb)Ys>Myt^;#1&a%O@x8A+E>! zY8=eD`ZG)LVagDLBeHg>=atOG?Kr%h4B%E6m@J^C+U|y)XX@f z8oyJDW|9g=<#f<{JRr{y#~euMnv)`7j=%cHWLc}ngjq~7k**6%4u>Px&W%4D94(r* z+akunK}O0DC2A%Xo9jyF;DobX?!1I(7%}@7F>i%&nk*LMO)bMGg2N+1iqtg+r(70q zF5{Msgsm5GS7DT`kBsjMvOrkx&|EU!{{~gL4d2MWrAT=KBQ-^zQCUq{5PD1orxlIL zq;CvlWx#f1NWvh`hg011I%?T_s!e38l*lWVt|~z-PO4~~1g)SrJ|>*tXh=QfXT)%( z+ex+inPvD&O4Ur;JGz>$sUOnWdpSLcm1X%aQDw4{dB!cnj`^muI$CJ2%p&-kULVCE z>$eMR36kN$wCPR+OFDM3-U(VOrp9k3)lI&YVFqd;Kpz~K)@Fa&FRw}L(SoD z9B4a+hQzZT-BnVltst&=kq6Y(f^S4hIGNKYBgMxGJ^;2yrO}P3;r)(-I-CZ)26Y6? z&rzHI_1GCvGkgy-t1E;r^3Le30|%$ebDRu2+gdLG)r=A~Qz`}~&L@aGJ{}vVs_GE* zVUjFnzHiXfKQbpv&bR&}l2bzIjAooB)=-XNcYmrGmBh(&iu@o!^hn0^#}m2yZZUK8 zufVm7Gq0y`Mj;9b>`c?&PZkU0j4>IL=UL&-Lp3j&47B5pAW4JceG{!XCA)kT<%2nqCxj<)uy6XR_uws~>_MEKPOpAQ!H zkn>FKh)<9DwwS*|Y(q?$^N!6(51O0 z^JM~Ax{AI1Oj$fs-S5d4T7Z_i1?{%0SsIuQ&r8#(JA=2iLcTN+?>wOL532%&dMYkT z*T5xepC+V6zxhS@vNbMoi|i)=rpli@R9~P!39tWbSSb904ekv7D#quKbgFEMTb48P zuq(VJ+&L8aWU(_FCD$3^uD!YM%O^K(dvy~Wm2hUuh6bD|#(I39Xt>N1Y{ZqXL`Fg6 zKQ?T2htHN!(Bx;tV2bfTtIj7e)liN-29s1kew>v(D^@)#v;}C4-G=7x#;-dM4yRWm zyY`cS21ulzMK{PoaQ6xChEZ}o_#}X-o}<&0)$1#3we?+QeLt;aVCjeA)hn!}UaKt< zat1fHEx13y-rXNMvpUUmCVzocPmN~-Y4(YJvQ#db)4|%B!rBsgAe+*yor~}FrNH08 z3V!97S}D7d$zbSD{$z;@IYMxM6aHdypIuS*pr_U6;#Y!_?0i|&yU*@16l z*dcMqDQgfNBf}?quiu4e>H)yTVfsp#f+Du0@=Kc41QockXkCkvu>FBd6Q+@FL!(Yx z2`YuX#eMEiLEDhp+9uFqME_E^faV&~9qjBHJkIp~%$x^bN=N)K@kvSVEMdDuzA0sn z88CBG?`RX1@#hQNd`o^V{37)!w|nA)QfiYBE^m=yQKv-fQF+UCMcuEe1d4BH7$?>b zJl-r9@0^Ie=)guO1vOd=i$_4sz>y3x^R7n4ED!5oXL3@5**h(xr%Hv)_gILarO46q+MaDOF%ChaymKoI6JU5Pg;7#2n9-18|S1;AK+ zgsn6;k6-%!QD>D?cFy}8F;r@z8H9xN1jsOBw2vQONVqBVEbkiNUqgw~*!^##ht>w0 zUOykwH=$LwX2j&nLy=@{hr)2O&-wm-NyjW7n~Zs9UlH;P7iP3 zI}S(r0YFVYacnKH(+{*)Tbw)@;6>%=&Th=+Z6NHo_tR|JCI8TJiXv2N7ei7M^Q+RM z?9o`meH$5Yi;@9XaNR#jIK^&{N|DYNNbtdb)XW1Lv2k{E>;?F`#Pq|&_;gm~&~Zc9 zf+6ZE%{x4|{YdtE?a^gKyzr}dA>OxQv+pq|@IXL%WS0CiX!V zm$fCePA%lU{%pTKD7|5NJHeXg=I0jL@$tOF@K*MI$)f?om)D63K*M|r`gb9edD1~Y zc|w7N)Y%do7=0{RC|AziW7#am$)9jciRJ?IWl9PE{G3U+$%FcyKs_0Cgq`=K3@ttV z9g;M!3z~f_?P%y3-ph%vBMeS@p7P&Ea8M@97+%XEj*(1E6vHj==d zjsoviB>j^$_^OI_DEPvFkVo(BGRo%cJeD){6Uckei=~1}>sp299|IRjhXe)%?uP0I zF5+>?0#Ye}T^Y$u_rc4=lPcq4K^D(TZG-w30-YiEM=dcK+4#o*>lJ8&JLi+3UcpZk z!^?95S^C0ja^jwP`|{<+3cBVog$(mRdQmadS+Vh~z zS@|P}=|z3P6uS+&@QsMp0no9Od&27O&14zHXGAOEy zh~OKpymK5C%;LLb467@KgIiVwYbYd6wFxI{0-~MOGfTq$nBTB!{SrWmL9Hs}C&l&l#m?s*{tA?BHS4mVKHAVMqm63H<|c5n0~k)-kbg zXidai&9ZUy0~WFYYKT;oe~rytRk?)r8bptITsWj(@HLI;@=v5|XUnSls7$uaxFRL+ zRVMGuL3w}NbV1`^=Pw*0?>bm8+xfeY(1PikW*PB>>Tq(FR`91N0c2&>lL2sZo5=VD zQY{>7dh_TX98L2)n{2OV=T10~*YzX27i2Q7W86M4$?gZIXZaBq#sA*{PH8){|GUi;oM>e?ua7eF4WFuFYZSG| zze?srg|5Ti8Og{O zeFxuw9!U+zhyk?@w zjsA6(oKD=Ka;A>Ca)oPORxK+kxH#O@zhC!!XS4@=swnuMk>t+JmLmFiE^1aX3f<)D@`%K0FGK^gg1a1j>zi z2KhV>sjU7AX3F$SEqrXSC}fRx64GDoc%!u2Yag68Lw@w9v;xOONf@o)Lc|Uh3<21ctTYu-mFZuHk*+R{GjXHIGq3p)tFtQp%TYqD=j1&y)>@zxoxUJ!G@ zgI0XKmP6MNzw>nRxK$-Gbzs}dyfFzt>#5;f6oR27ql!%+{tr+(`(>%51|k`ML} zY4eE)Lxq|JMas(;JibNQds1bUB&r}ydMQXBY4x(^&fY_&LlQC)3hylc$~8&~|06-D z#T+%66rYbHX%^KuqJED_wuGB+=h`nWA!>1n0)3wZrBG3%`b^Ozv6__dNa@%V14|!D zQ?o$z5u0^8`giv%qE!BzZ!3j;BlDlJDk)h@9{nSQeEk!z9RGW) z${RSF3phEM*ce*>Xdp}585vj$|40=&S{S-GTiE?Op*vY&Lvr9}BO$XWy80IF+6@%n z5*2ueT_g@ofP#u5pxb7n*fv^Xtt7&?SRc{*2Ka-*!BuOpf}neHGCiHy$@Ka1^Dint z;DkmIL$-e)rj4o2WQV%Gy;Xg(_Bh#qeOsTM2f@KEe~4kJ8kNLQ+;(!j^bgJMcNhvklP5Z6I+9Fq@c&D~8Fb-4rmDT!MB5QC{Dsb;BharP*O;SF4& zc$wj-7Oep7#$WZN!1nznc@Vb<_Dn%ga-O#J(l=OGB`dy=Sy&$(5-n3zzu%d7E#^8`T@}V+5B;PP8J14#4cCPw-SQTdGa2gWL0*zKM z#DfSXs_iWOMt)0*+Y>Lkd=LlyoHjublNLefhKBv@JoC>P7N1_#> zv=mLWe96%EY;!ZGSQDbZWb#;tzqAGgx~uk+-$+2_8U`!ypbwXl z^2E-FkM1?lY@yt8=J3%QK+xaZ6ok=-y%=KXCD^0r!5vUneW>95PzCkOPO*t}p$;-> ze5j-BLT_;)cZQzR2CEsm@rU7GZfFtdp*a|g4wDr%8?2QkIGasRfDWT-Dvy*U{?IHT z*}wGnzdlSptl#ZF^sf)KT|BJs&kLG91^A6ls{CzFprZ6-Y!V0Xysh%9p%iMd7HLsS zN+^Un$tDV)T@i!v?3o0Fsx2qI(AX_$dDkBzQ@fRM%n zRXk6hb9Py#JXUs+7)w@eo;g%QQ95Yq!K_d=z{0dGS+pToEI6=Bo8+{k$7&Z zo4>PH(`ce8E-Ps&uv`NQ;U$%t;w~|@E3WVOCi~R4oj5wP?%<*1C%}Jq%a^q~T7u>K zML5AKfQDv6>PuT`{SrKHRAF+^&edg6+5R_#H?Lz3iGoWo#PCEd0DS;)2U({{X#zU^ zw_xv{4x7|t!S)>44J;KfA|DC?;uQ($l+5Vp7oeqf7{GBF9356nx|&B~gs+@N^gSdd zvb*>&W)|u#F{Z_b`f#GVtQ`pYv3#||N{xj1NgB<#=Odt6{eB%#9RLt5v zIi|0u70`#ai}9fJjKv7dE!9ZrOIX!3{$z_K5FBd-Kp-&e4(J$LD-)NMTp^_pB`RT; zftVVlK2g@+1Ahv2$D){@Y#cL#dUj9*&%#6 zd2m9{1NYp>)6=oAvqdCn5#cx{AJ%S8skUgMglu2*IAtd+z1>B&`MuEAS(D(<6X#Lj z?f4CFx$)M&$=7*>9v1ER4b6!SIz-m0e{o0BfkySREchp?WdVPpQCh!q$t>?rL!&Jg zd#heM;&~A}VEm8Dvy&P|J*eAV&w!&Nx6HFV&B8jJFVTmgLaswn!cx$&%JbTsloz!3 zMEz1d`k==`Ueub_JAy_&`!ogbwx27^ZXgFNAbx=g_I~5nO^r)}&myw~+yY*cJl4$I znNJ32M&K=0(2Dj_>@39`3=FX!v3nZHno_@q^!y}%(yw0PqOo=);6Y@&ylVe>nMOZ~ zd>j#QQSBn3oaWd;qy$&5(5H$Ayi)0haAYO6TH>FR?rhqHmNOO+(})NB zLI@B@v0)eq!ug`>G<@htRlp3n!EpU|n+G+AvXFrWSUsLMBfL*ZB`CRsIVHNTR&b?K zxBgsN0BjfB>UVcJ|x%=-zb%OV7lmZc& zxiupadZVF7)6QuhoY;;FK2b*qL0J-Rn-8!X4ZY$-ZSUXV5DFd7`T41c(#lAeLMoeT z4%g655v@7AqT!i@)Edt5JMbN(=Q-6{=L4iG8RA%}w;&pKmtWvI4?G9pVRp|RTw`g0 zD5c12B&A2&P6Ng~8WM2eIW=wxd?r7A*N+&!Be7PX3s|7~z=APxm=A?5 zt>xB4WG|*Td@VX{Rs)PV0|yK`oI3^xn(4c_j&vgxk_Y3o(-`_5o`V zRTghg6%l@(qodXN;dB#+OKJEEvhfcnc#BeO2|E(5df-!fKDZ!%9!^BJ_4)9P+9Dq5 zK1=(v?KmIp34r?z{NEWnLB3Px{XYwy-akun4F7xTRr2^zeYW{gcK9)>aJDdU5;w5@ zak=<+-PLH-|04pelTb%ULpuuuJC7DgyT@D|p{!V!0v3KpDnRjANN12q6SUR3mb9<- z>2r~IApQGhstZ!3*?5V z8#)hJ0TdZg0M-BK#nGFP>$i=qk82DO z7h;Ft!D5E15OgW)&%lej*?^1~2=*Z5$2VX>V{x8SC+{i10BbtUk9@I#Vi&hX)q
Q!LwySI{Bnv%Sm)yh{^sSVJ8&h_D-BJ_YZe5eCaAWU9b$O2c z$T|{vWVRtOL!xC0DTc(Qbe`ItNtt5hr<)VijD0{U;T#bUEp381_y`%ZIav?kuYG{iyYdEBPW=*xNSc;Rlt6~F4M`5G+VtOjc z*0qGzCb@gME5udTjJA-9O<&TWd~}ysBd(eVT1-H82-doyH9RST)|+Pb{o*;$j9Tjs zhU!IlsPsj8=(x3bAKJTopW3^6AKROHR^7wZ185wJGVhA~hEc|LP;k7NEz-@4p5o}F z`AD6naG3(n=NF9HTH81=F+Q|JOz$7wm9I<+#BSmB@o_cLt2GkW9|?7mM;r!JZp89l zbo!Hp8=n!XH1{GwaDU+k)pGp`C|cXkCU5%vcH)+v@0eK>%7gWxmuMu9YLlChA|_D@ zi#5zovN_!a-0?~pUV-Rj*1P)KwdU-LguR>YM&*Nen+ln8Q$?WFCJg%DY%K}2!!1FE zDv-A%Cbwo^p(lzac&_TZ-l#9kq`mhLcY3h9ZTUVCM(Ad&=EriQY5{jJv<5K&g|*Lk zgV%ILnf1%8V2B0E&;Sp4sYbYOvvMebLwYwzkRQ#F8GpTQq#uv=J`uaSJ34OWITeSGo6+-8Xw znCk*n{kdDEi)Hi&u^)~cs@iyCkFWB2SWZU|Uc%^43ZIZQ-vWNExCCtDWjqHs;;tWf$v{}0{p0Rvxkq``)*>+Akq%|Na zA`@~-Vfe|+(AIlqru+7Ceh4nsVmO9p9jc8}HX^W&ViBDXT+uXbT#R#idPn&L>+#b6 zflC-4C5-X;kUnR~L>PSLh*gvL68}RBsu#2l`s_9KjUWRhiqF`j)`y`2`YU(>3bdBj z?>iyjEhe-~$^I5!nn%B6Wh+I`FvLNvauve~eX<+Ipl&04 zT}};W&1a3%W?dJ2=N#0t?e+aK+%t}5q%jSLvp3jZ%?&F}nOOWr>+{GFIa%wO_2`et z=JzoRR~}iKuuR+azPI8;Gf9)z3kyA4EIOSl!sRR$DlW}0>&?GbgPojmjmnln;cTqCt=ADbE zZ8GAnoM+S1(5$i8^O4t`ue;vO4i}z0wz-QEIVe5_u03;}-!G1NyY8;h^}y;tzY}i5 zqQr#Ur3Fy8sSa$Q0ys+f`!`+>9WbvU_I`Sj;$4{S>O3?#inLHCrtLy~!s#WXV=oVP zeE93*Nc`PBi4q@%Ao$x4lw9vLHM!6mn3-b_cebF|n-2vt-zYVF_&sDE--J-P;2WHo z+@n2areE0o$LjvjlV2X7ZU@j+`{*8zq`JR3gKF#EW|#+{nMyo-a>nFFTg&vhyT=b} zDa8+v0(Dgx0yRL@ZXOYIlVSZ0|MFizy0VPW8;AfA5|pe!#j zX}Py^8fl5SyS4g1WSKKtnyP+_PoOwMMwu`(i@Z)diJp~U54*-miOchy7Z35eL>^M z4p<-aIxH4VUZgS783@H%M7P9hX>t{|RU7$n4T(brCG#h9e9p! z+o`i;EGGq3&pF;~5V~eBD}lC)>if$w%Vf}AFxGqO88|ApfHf&Bvu+xdG)@vuF}Yvk z)o;~k-%+0K0g+L`Wala!$=ZV|z$e%>f0%XoLib%)!R^RoS+{!#X?h-6uu zF&&KxORdZU&EwQFITIRLo(7TA3W}y6X{?Y%y2j0It!ekU#<)$qghZtpcS>L3uh`Uj z7GY;6f$9qKynP#oS3$$a{p^{D+0oJQ71`1?OAn_m8)UGZmj3l*ZI)`V-a>MKGGFG< z&^jg#Ok%(hhm>hSrZ5;Qga4u(?^i>GiW_j9%_7M>j(^|Om$#{k+^*ULnEgzW_1gCICtAD^WpC`A z{9&DXkG#01Xo)U$OC(L5Y$DQ|Q4C6CjUKk1UkPj$nXH##J{c8e#K|&{mA*;b$r0E4 zUNo0jthwA(c&N1l=PEe8Rw_8cEl|-eya9z&H3#n`B$t#+aJ03RFMzrV@gowbe8v(c zIFM60^0&lCFO10NU4w@|61xiZ4CVXeaKjd;d?sv52XM*lS8XiVjgWpRB;&U_C0g+`6B5V&w|O6B*_q zsATxL!M}+$He)1eOWECce#eS@2n^xhlB4<_Nn?yCVEQWDs(r`|@2GqLe<#(|&P0U? z$7V5IgpWf09uIf_RazRwC?qEqRaHyL?iiS05UiGesJy%^>-C{{ypTBI&B0-iUYhk> zIk<5xpsuV@g|z(AZD+C-;A!fTG=df1=<%nxy(a(IS+U{ME4ZbDEBtcD_3V=icT6*_ z)>|J?>&6%nvHhZERBtjK+s4xnut*@>GAmA5m*OTp$!^CHTr}vM4n(X1Q*;{e-Rd2BCF-u@1ZGm z!S8hJ6L=Gl4T_SDa7Xx|-{4mxveJg=ctf`BJ*fy!yF6Dz&?w(Q_6B}WQVtNI!BVBC zKfX<>7vd6C96}XAQmF-Jd?1Q4eTfRB3q7hCh0f!(JkdWT5<{iAE#dKy*Jxq&3a1@~ z8C||Dn2mFNyrUV|<-)C^_y7@8c2Fz+2jrae9deBDu;U}tJ{^xAdxCD248(k;dCJ%o z`y3sADe>U%suxwwv~8A1+R$VB=Q?%U?4joI$um;aH+eCrBqpn- z%79D_7rb;R-;-9RTrwi9dPlg8&@tfWhhZ(Vx&1PQ+6(huX`;M9x~LrW~~#3{j0Bh2kDU$}@!fFQej4VGkJv?M4rU^x!RU zEwhu$!CA_iDjFjrJa`aocySDX16?~;+wgav;}Zut6Mg%C4>}8FL?8)Kgwc(Qlj{@#2Pt0?G`$h7P#M+qoXtlV@d}%c&OzO+QYKK`kyXaK{U(O^2DyIXCZlNQjt0^8~8JzNGrIxhj}}M z&~QZlbx%t;MJ(Vux;2tgNKGlAqphLq%pd}JG9uoVHUo?|hN{pLQ6Em%r*+7t^<);X zm~6=qChlNAVXNN*Sow->*4;}T;l;D1I-5T{Bif@4_}=>l`tK;qqDdt5zvisCKhMAH z#r}`)7VW?LZqfdmXQ%zo5bJ00{Xb9^YKrk0Nf|oIW*K@(=`o2Vndz}ZDyk{!u}PVx zzd--+_WC*U{~DH3{?GI64IB+@On&@9X>EUAo&L+G{L^dozaI4C3G#2wr~hseW@K&g zKWs{uHu-9Je!3;4pE>eBltKUXb^*hG8I&413)$J&{D4N%7PcloU6bn%jPxJyQL?g* z9g+YFFEDiE`8rW^laCNzQmi7CTnPfwyg3VDHRAl>h=In6jeaVOP@!-CP60j3+#vpL zEYmh_oP0{-gTe7Or`L6x)6w?77QVi~jD8lWN@3RHcm80iV%M1A!+Y6iHM)05iC64tb$X2lV_%Txk@0l^hZqi^%Z?#- zE;LE0uFx)R08_S-#(wC=dS&}vj6P4>5ZWjhthP=*Hht&TdLtKDR;rXEX4*z0h74FA zMCINqrh3Vq;s%3MC1YL`{WjIAPkVL#3rj^9Pj9Ss7>7duy!9H0vYF%>1jh)EPqvlr6h%R%CxDsk| z!BACz7E%j?bm=pH6Eaw{+suniuY7C9Ut~1cWfOX9KW9=H><&kQlinPV3h9R>3nJvK z4L9(DRM=x;R&d#a@oFY7mB|m8h4692U5eYfcw|QKwqRsshN(q^v$4$)HgPpAJDJ`I zkqjq(8Cd!K!+wCd=d@w%~e$=gdUgD&wj$LQ1r>-E=O@c ze+Z$x{>6(JA-fNVr)X;*)40Eym1TtUZI1Pwwx1hUi+G1Jlk~vCYeXMNYtr)1?qwyg zsX_e*$h?380O00ou?0R@7-Fc59o$UvyVs4cUbujHUA>sH!}L54>`e` zHUx#Q+Hn&Og#YVOuo*niy*GU3rH;%f``nk#NN5-xrZ34NeH$l`4@t);4(+0|Z#I>Y z)~Kzs#exIAaf--65L0UHT_SvV8O2WYeD>Mq^Y6L!Xu8%vnpofG@w!}R7M28?i1*T&zp3X4^OMCY6(Dg<-! zXmcGQrRgHXGYre7GfTJ)rhl|rs%abKT_Nt24_Q``XH{88NVPW+`x4ZdrMuO0iZ0g` z%p}y};~T5gbb9SeL8BSc`SO#ixC$@QhXxZ=B}L`tP}&k?1oSPS=4%{UOHe0<_XWln zwbl5cn(j-qK`)vGHY5B5C|QZd5)W7c@{bNVXqJ!!n$^ufc?N9C-BF2QK1(kv++h!>$QbAjq)_b$$PcJdV+F7hz0Hu@ zqj+}m0qn{t^tD3DfBb~0B36|Q`bs*xs|$i^G4uNUEBl4g;op-;Wl~iThgga?+dL7s zUP(8lMO?g{GcYpDS{NM!UA8Hco?#}eNEioRBHy4`mq!Pd-9@-97|k$hpEX>xoX+dY zDr$wfm^P&}Wu{!%?)U_(%Mn79$(ywvu*kJ9r4u|MyYLI_67U7%6Gd_vb##Nerf@>& z8W11z$$~xEZt$dPG}+*IZky+os5Ju2eRi;1=rUEeIn>t-AzC_IGM-IXWK3^6QNU+2pe=MBn4I*R@A%-iLDCOHTE-O^wo$sL_h{dcPl=^muAQb`_BRm};=cy{qSkui;`WSsj9%c^+bIDQ z0`_?KX0<-=o!t{u(Ln)v>%VGL z0pC=GB7*AQ?N7N{ut*a%MH-tdtNmNC+Yf$|KS)BW(gQJ*z$d{+{j?(e&hgTy^2|AR9vx1Xre2fagGv0YXWqtNkg*v%40v?BJBt|f9wX5 z{QTlCM}b-0{mV?IG>TW_BdviUKhtosrBqdfq&Frdz>cF~yK{P@(w{Vr7z2qKFwLhc zQuogKO@~YwyS9%+d-zD7mJG~@?EFJLSn!a&mhE5$_4xBl&6QHMzL?CdzEnC~C3$X@ zvY!{_GR06ep5;<#cKCSJ%srxX=+pn?ywDwtJ2{TV;0DKBO2t++B(tIO4)Wh`rD13P z4fE$#%zkd=UzOB74gi=-*CuID&Z3zI^-`4U^S?dHxK8fP*;fE|a(KYMgMUo`THIS1f!*6dOI2 zFjC3O=-AL`6=9pp;`CYPTdVX z8(*?V&%QoipuH0>WKlL8A*zTKckD!paN@~hh zmXzm~qZhMGVdQGd=AG8&20HW0RGV8X{$9LldFZYm zE?}`Q3i?xJRz43S?VFMmqRyvWaS#(~Lempg9nTM$EFDP(Gzx#$r)W&lpFKqcAoJh-AxEw$-bjW>`_+gEi z2w`99#UbFZGiQjS8kj~@PGqpsPX`T{YOj`CaEqTFag;$jY z8_{Wzz>HXx&G*Dx<5skhpETxIdhKH?DtY@b9l8$l?UkM#J-Snmts7bd7xayKTFJ(u zyAT&@6cAYcs{PBfpqZa%sxhJ5nSZBPji?Zlf&}#L?t)vC4X5VLp%~fz2Sx<*oN<7` z?ge=k<=X7r<~F7Tvp9#HB{!mA!QWBOf%EiSJ6KIF8QZNjg&x~-%e*tflL(ji_S^sO ztmib1rp09uon}RcsFi#k)oLs@$?vs(i>5k3YN%$T(5Or(TZ5JW9mA6mIMD08=749$ z!d+l*iu{Il7^Yu}H;lgw=En1sJpCKPSqTCHy4(f&NPelr31^*l%KHq^QE>z>Ks_bH zjbD?({~8Din7IvZeJ>8Ey=e;I?thpzD=zE5UHeO|neioJwG;IyLk?xOz(yO&0DTU~ z^#)xcs|s>Flgmp;SmYJ4g(|HMu3v7#;c*Aa8iF#UZo7CvDq4>8#qLJ|YdZ!AsH%^_7N1IQjCro

K7UpUK$>l@ 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 E2O(~oYXATM diff --git a/android/test_backup/ClimbRepository.kt b/android/test_backup/ClimbRepository.kt new file mode 100644 index 0000000..fe3483c --- /dev/null +++ b/android/test_backup/ClimbRepository.kt @@ -0,0 +1,383 @@ +package com.atridad.openclimb.data.repository + +import android.content.Context +import com.atridad.openclimb.data.database.OpenClimbDatabase +import com.atridad.openclimb.data.format.ClimbDataBackup +import com.atridad.openclimb.data.model.* +import com.atridad.openclimb.utils.ZipExportImportUtils +import java.io.File +import java.time.LocalDateTime +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.serialization.json.Json + +class ClimbRepository(database: OpenClimbDatabase, private val context: Context) { + private val gymDao = database.gymDao() + private val problemDao = database.problemDao() + private val sessionDao = database.climbSessionDao() + private val attemptDao = database.attemptDao() + + private val json = Json { + prettyPrint = true + ignoreUnknownKeys = true + } + + // Gym operations + fun getAllGyms(): Flow> = gymDao.getAllGyms() + suspend fun getGymById(id: String): Gym? = gymDao.getGymById(id) + suspend fun insertGym(gym: Gym) = gymDao.insertGym(gym) + suspend fun updateGym(gym: Gym) = gymDao.updateGym(gym) + suspend fun deleteGym(gym: Gym) = gymDao.deleteGym(gym) + fun searchGyms(query: String): Flow> = gymDao.searchGyms(query) + + // Problem operations + fun getAllProblems(): Flow> = problemDao.getAllProblems() + suspend fun getProblemById(id: String): Problem? = problemDao.getProblemById(id) + fun getProblemsByGym(gymId: String): Flow> = problemDao.getProblemsByGym(gymId) + suspend fun insertProblem(problem: Problem) = problemDao.insertProblem(problem) + suspend fun updateProblem(problem: Problem) = problemDao.updateProblem(problem) + suspend fun deleteProblem(problem: Problem) = problemDao.deleteProblem(problem) + fun searchProblems(query: String): Flow> = problemDao.searchProblems(query) + + // Session operations + fun getAllSessions(): Flow> = sessionDao.getAllSessions() + suspend fun getSessionById(id: String): ClimbSession? = sessionDao.getSessionById(id) + fun getSessionsByGym(gymId: String): Flow> = + sessionDao.getSessionsByGym(gymId) + suspend fun getActiveSession(): ClimbSession? = sessionDao.getActiveSession() + fun getActiveSessionFlow(): Flow = sessionDao.getActiveSessionFlow() + suspend fun insertSession(session: ClimbSession) = sessionDao.insertSession(session) + suspend fun updateSession(session: ClimbSession) = sessionDao.updateSession(session) + suspend fun deleteSession(session: ClimbSession) = sessionDao.deleteSession(session) + suspend fun getLastUsedGym(): Gym? { + val recentSessions = sessionDao.getRecentSessions(1).first() + return if (recentSessions.isNotEmpty()) { + getGymById(recentSessions.first().gymId) + } else { + null + } + } + + // Attempt operations + fun getAllAttempts(): Flow> = attemptDao.getAllAttempts() + fun getAttemptsBySession(sessionId: String): Flow> = + attemptDao.getAttemptsBySession(sessionId) + fun getAttemptsByProblem(problemId: String): Flow> = + attemptDao.getAttemptsByProblem(problemId) + suspend fun insertAttempt(attempt: Attempt) = attemptDao.insertAttempt(attempt) + suspend fun updateAttempt(attempt: Attempt) = attemptDao.updateAttempt(attempt) + suspend fun deleteAttempt(attempt: Attempt) = attemptDao.deleteAttempt(attempt) + + // ZIP Export with images - Single format for reliability + suspend fun exportAllDataToZip(directory: File? = null): File { + return try { + // Collect all data with proper error handling + val allGyms = gymDao.getAllGyms().first() + val allProblems = problemDao.getAllProblems().first() + val allSessions = sessionDao.getAllSessions().first() + val allAttempts = attemptDao.getAllAttempts().first() + + // Validate data integrity before export + validateDataIntegrity(allGyms, allProblems, allSessions, allAttempts) + + // Create backup data using platform-neutral format + val backupData = + ClimbDataBackup( + exportedAt = LocalDateTime.now().toString(), + version = "2.0", + formatVersion = "2.0", + gyms = + allGyms.map { + com.atridad.openclimb.data.format.BackupGym.fromGym(it) + }, + problems = + allProblems.map { + com.atridad.openclimb.data.format.BackupProblem.fromProblem( + it + ) + }, + sessions = + allSessions.map { + com.atridad.openclimb.data.format.BackupClimbSession + .fromClimbSession(it) + }, + attempts = + allAttempts.map { + com.atridad.openclimb.data.format.BackupAttempt.fromAttempt( + it + ) + } + ) + + // Collect all referenced image paths and validate they exist + val referencedImagePaths = allProblems.flatMap { it.imagePaths }.toSet() + val validImagePaths = + referencedImagePaths + .filter { imagePath -> + try { + val imageFile = + com.atridad.openclimb.utils.ImageUtils.getImageFile( + context, + imagePath + ) + imageFile.exists() && imageFile.length() > 0 + } catch (e: Exception) { + false + } + } + .toSet() + + // Log any missing images for debugging + val missingImages = referencedImagePaths - validImagePaths + if (missingImages.isNotEmpty()) { + android.util.Log.w( + "ClimbRepository", + "Some referenced images are missing: $missingImages" + ) + } + + ZipExportImportUtils.createExportZip( + context = context, + exportData = backupData, + referencedImagePaths = validImagePaths, + directory = directory + ) + } catch (e: Exception) { + throw Exception("Export failed: ${e.message}") + } + } + + suspend fun exportAllDataToZipUri(uri: android.net.Uri) { + try { + // Collect all data + val allGyms = gymDao.getAllGyms().first() + val allProblems = problemDao.getAllProblems().first() + val allSessions = sessionDao.getAllSessions().first() + val allAttempts = attemptDao.getAllAttempts().first() + + // Validate data integrity before export + validateDataIntegrity(allGyms, allProblems, allSessions, allAttempts) + + // Create backup data using platform-neutral format + val backupData = + ClimbDataBackup( + exportedAt = LocalDateTime.now().toString(), + version = "2.0", + formatVersion = "2.0", + gyms = + allGyms.map { + com.atridad.openclimb.data.format.BackupGym.fromGym(it) + }, + problems = + allProblems.map { + com.atridad.openclimb.data.format.BackupProblem.fromProblem( + it + ) + }, + sessions = + allSessions.map { + com.atridad.openclimb.data.format.BackupClimbSession + .fromClimbSession(it) + }, + attempts = + allAttempts.map { + com.atridad.openclimb.data.format.BackupAttempt.fromAttempt( + it + ) + } + ) + + // Collect all referenced image paths and validate they exist + val referencedImagePaths = allProblems.flatMap { it.imagePaths }.toSet() + val validImagePaths = + referencedImagePaths + .filter { imagePath -> + try { + val imageFile = + com.atridad.openclimb.utils.ImageUtils.getImageFile( + context, + imagePath + ) + imageFile.exists() && imageFile.length() > 0 + } catch (e: Exception) { + false + } + } + .toSet() + + ZipExportImportUtils.createExportZipToUri( + context = context, + uri = uri, + exportData = backupData, + referencedImagePaths = validImagePaths + ) + } catch (e: Exception) { + throw Exception("Export failed: ${e.message}") + } + } + + suspend fun importDataFromZip(file: File) { + try { + // Validate the ZIP file + if (!file.exists() || file.length() == 0L) { + throw Exception("Invalid ZIP file: file is empty or doesn't exist") + } + + // Extract and validate the ZIP contents + val importResult = ZipExportImportUtils.extractImportZip(context, file) + + // Validate JSON content + if (importResult.jsonContent.isBlank()) { + throw Exception("Invalid ZIP file: no data.json found or empty content") + } + + // Parse and validate the data structure + val importData = + try { + json.decodeFromString(importResult.jsonContent) + } catch (e: Exception) { + throw Exception("Invalid data format: ${e.message}") + } + + // Validate data integrity + validateImportData(importData) + + // Clear existing data to avoid conflicts + attemptDao.deleteAllAttempts() + sessionDao.deleteAllSessions() + problemDao.deleteAllProblems() + gymDao.deleteAllGyms() + + // Import gyms first (problems depend on gyms) + importData.gyms.forEach { backupGym -> + try { + gymDao.insertGym(backupGym.toGym()) + } catch (e: Exception) { + throw Exception("Failed to import gym '${backupGym.name}': ${e.message}") + } + } + + // Import problems with updated image paths + val updatedBackupProblems = + ZipExportImportUtils.updateProblemImagePaths( + importData.problems, + importResult.importedImagePaths + ) + + // Import problems (depends on gyms) + updatedBackupProblems.forEach { backupProblem -> + try { + problemDao.insertProblem(backupProblem.toProblem()) + } catch (e: Exception) { + throw Exception( + "Failed to import problem '${backupProblem.name}': ${e.message}" + ) + } + } + + // Import sessions + importData.sessions.forEach { backupSession -> + try { + sessionDao.insertSession(backupSession.toClimbSession()) + } catch (e: Exception) { + throw Exception("Failed to import session '${backupSession.id}': ${e.message}") + } + } + + // Import attempts last (depends on problems and sessions) + importData.attempts.forEach { backupAttempt -> + try { + attemptDao.insertAttempt(backupAttempt.toAttempt()) + } catch (e: Exception) { + throw Exception("Failed to import attempt '${backupAttempt.id}': ${e.message}") + } + } + } catch (e: Exception) { + throw Exception("Import failed: ${e.message}") + } + } + + private fun validateDataIntegrity( + gyms: List, + problems: List, + sessions: List, + attempts: List + ) { + // Validate that all problems reference valid gyms + val gymIds = gyms.map { it.id }.toSet() + val invalidProblems = problems.filter { it.gymId !in gymIds } + if (invalidProblems.isNotEmpty()) { + throw Exception( + "Data integrity error: ${invalidProblems.size} problems reference non-existent gyms" + ) + } + + // Validate that all sessions reference valid gyms + val invalidSessions = sessions.filter { it.gymId !in gymIds } + if (invalidSessions.isNotEmpty()) { + throw Exception( + "Data integrity error: ${invalidSessions.size} sessions reference non-existent gyms" + ) + } + + // Validate that all attempts reference valid problems and sessions + val problemIds = problems.map { it.id }.toSet() + val sessionIds = sessions.map { it.id }.toSet() + + val invalidAttempts = + attempts.filter { it.problemId !in problemIds || it.sessionId !in sessionIds } + if (invalidAttempts.isNotEmpty()) { + throw Exception( + "Data integrity error: ${invalidAttempts.size} attempts reference non-existent problems or sessions" + ) + } + } + + private fun validateImportData(importData: ClimbDataBackup) { + if (importData.gyms.isEmpty()) { + throw Exception("Import data is invalid: no gyms found") + } + + if (importData.version.isBlank()) { + throw Exception("Import data is invalid: no version information") + } + + // Check for reasonable data sizes to prevent malicious imports + if (importData.gyms.size > 1000 || + importData.problems.size > 10000 || + importData.sessions.size > 10000 || + importData.attempts.size > 100000 + ) { + throw Exception("Import data is too large: possible corruption or malicious file") + } + } + + suspend fun resetAllData() { + try { + // Clear all data from database + attemptDao.deleteAllAttempts() + sessionDao.deleteAllSessions() + problemDao.deleteAllProblems() + gymDao.deleteAllGyms() + + // Clear all images from storage + clearAllImages() + } catch (e: Exception) { + throw Exception("Reset failed: ${e.message}") + } + } + + private fun clearAllImages() { + try { + // Get the images directory + val imagesDir = File(context.filesDir, "images") + if (imagesDir.exists() && imagesDir.isDirectory) { + val deletedCount = imagesDir.listFiles()?.size ?: 0 + imagesDir.deleteRecursively() + android.util.Log.i("ClimbRepository", "Cleared $deletedCount image files") + } + } catch (e: Exception) { + android.util.Log.w("ClimbRepository", "Failed to clear some images: ${e.message}") + } + } +} diff --git a/ios/OpenClimb.xcodeproj/project.pbxproj b/ios/OpenClimb.xcodeproj/project.pbxproj index f8e7793..0a60cb7 100644 --- a/ios/OpenClimb.xcodeproj/project.pbxproj +++ b/ios/OpenClimb.xcodeproj/project.pbxproj @@ -394,7 +394,7 @@ CODE_SIGN_ENTITLEMENTS = OpenClimb/OpenClimb.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = 4BC9Y2LL4B; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -414,7 +414,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.3; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -437,7 +437,7 @@ CODE_SIGN_ENTITLEMENTS = OpenClimb/OpenClimb.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = 4BC9Y2LL4B; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; @@ -457,7 +457,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.3; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -479,7 +479,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = 4BC9Y2LL4B; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SessionStatusLive/Info.plist; @@ -490,7 +490,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.3; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb.SessionStatusLive; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -509,7 +509,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 9; + CURRENT_PROJECT_VERSION = 10; DEVELOPMENT_TEAM = 4BC9Y2LL4B; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SessionStatusLive/Info.plist; @@ -520,7 +520,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.0.3; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb.SessionStatusLive; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate b/ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate index 6acfc545a745e71e6ae926132a20c2b0aaf0705a..2f1b85e4b9d66a00a2d408c8053a913a3f8012f7 100644 GIT binary patch literal 117982 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 Xesh5z@j|NlRS8eRE6U59(z literal 115423 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%0AgJ)JPyYM&F& zX7*x6)sAw4vz+G=m-&}_K}hvX*kSd`m`nBlVIS4UGL7l{!c3N+x9ZCvcA?_T3+ z5aR#58d5VgX~{rle3v!de9bV-w5BXI>*M{Jk@!Aqj%Efj)Qn*ZTiK3#s;NfJTR})I zZ`SfwEpOGzi~ZE9&bxey_iA;;tZQ{+0AJ%9sx_SNaKp9Ct=2piuoyF|WoEV9P_1>S zTk9|~*RrEpa@TUdwI1-8lpv&b2%)4SBU#8!QHoQNGL)whRjEO3eD}5WT)Q(v`H{Jp zcWv2g?_xK5IfnYRPx2%PsbdCp)T@&THS3r`okF<9I>mUNQq-X-&1g;sdeDbR#m3t2@Bv6xLAJE>zfb#|b?I{R=>b@W!}4Cgq{4es*@cTv|})HSEN z`mU?zy5>~Z9_yM(T|28gky$KaDJzIZ?Yj0+cO&LfcN>4QlPf_;y-?(>SCN`DLgsp} z(SrZchR^sMnd`ZSdhVg#_o!R%C+4DVJ$37;ThAWqtwr5>>ef@Yp1SpRv4?9xNPT(g zm!=BU=*a*Eq38O3r@mR$zk?ane-?x^D1$y5G~oqa;#J<@Z9b+IZLzNg?xTVEG|+p4 zDd?qPYUFJA4I>%PBxdj%i;$sVBJ24Bdun))Q(VIA8r};+8f73e*|3jBVdSL%g(*sL z^xVkZHmXMh8qkw$~0E9hrff6ChosUG0ISm>gcseL(IB~SvS#Zla_qMr?jCx=G!ES z?)0J$`fjp|he1fwRD_ZPvuSEJP0gmM*);W?H7!d8DpM8TT~jyM^wl7w`GzIS%vS8N`Je3MW)SjH9^Ao8pJCoF4PZFm;hmSv=fA%< b&wu|2_5UC9-#-cu`G5cV|Nk2DQtbZ$GqODt diff --git a/ios/OpenClimb/ContentView.swift b/ios/OpenClimb/ContentView.swift index d99571e..ea9c62f 100644 --- a/ios/OpenClimb/ContentView.swift +++ b/ios/OpenClimb/ContentView.swift @@ -100,7 +100,7 @@ struct ContentView: View { print("📱 App did become active - checking Live Activity status") Task { try? await Task.sleep(nanoseconds: 300_000_000) // 0.3 seconds - dataManager.onAppBecomeActive() + await dataManager.onAppBecomeActive() } } diff --git a/ios/OpenClimb/Models/BackupFormat.swift b/ios/OpenClimb/Models/BackupFormat.swift new file mode 100644 index 0000000..1a0f95a --- /dev/null +++ b/ios/OpenClimb/Models/BackupFormat.swift @@ -0,0 +1,452 @@ +// +// BackupFormat.swift +// OpenClimb +// +// Created by OpenClimb Team on 2024-12-19. +// Copyright © 2024 OpenClimb. All rights reserved. +// + +import Foundation + +// MARK: - Backup Format Specification v2.0 +// Platform-neutral backup format for cross-platform compatibility +// This format ensures portability between iOS and Android while maintaining +// platform-specific implementations + +/// Root structure for OpenClimb backup data +struct ClimbDataBackup: Codable { + let exportedAt: String + let version: String + let formatVersion: String + let gyms: [BackupGym] + let problems: [BackupProblem] + let sessions: [BackupClimbSession] + let attempts: [BackupAttempt] + + init( + exportedAt: String, + version: String = "2.0", + formatVersion: String = "2.0", + gyms: [BackupGym], + problems: [BackupProblem], + sessions: [BackupClimbSession], + attempts: [BackupAttempt] + ) { + self.exportedAt = exportedAt + self.version = version + self.formatVersion = formatVersion + self.gyms = gyms + self.problems = problems + self.sessions = sessions + self.attempts = attempts + } +} + +/// Platform-neutral gym representation for backup/restore +struct BackupGym: Codable { + let id: String + let name: String + let location: String? + let supportedClimbTypes: [ClimbType] + let difficultySystems: [DifficultySystem] + let customDifficultyGrades: [String] + let notes: String? + let createdAt: String // ISO 8601 format + let updatedAt: String // ISO 8601 format + + /// Initialize from native iOS Gym model + init(from gym: Gym) { + self.id = gym.id.uuidString + self.name = gym.name + self.location = gym.location + self.supportedClimbTypes = gym.supportedClimbTypes + self.difficultySystems = gym.difficultySystems + self.customDifficultyGrades = gym.customDifficultyGrades + self.notes = gym.notes + + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + self.createdAt = formatter.string(from: gym.createdAt) + self.updatedAt = formatter.string(from: gym.updatedAt) + } + + /// Initialize with explicit parameters for import + init( + id: String, + name: String, + location: String?, + supportedClimbTypes: [ClimbType], + difficultySystems: [DifficultySystem], + customDifficultyGrades: [String] = [], + notes: String?, + createdAt: String, + updatedAt: String + ) { + self.id = id + self.name = name + self.location = location + self.supportedClimbTypes = supportedClimbTypes + self.difficultySystems = difficultySystems + self.customDifficultyGrades = customDifficultyGrades + self.notes = notes + self.createdAt = createdAt + self.updatedAt = updatedAt + } + + /// Convert to native iOS Gym model + func toGym() throws -> Gym { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + + guard let uuid = UUID(uuidString: id), + let createdDate = formatter.date(from: createdAt), + let updatedDate = formatter.date(from: updatedAt) + else { + throw BackupError.invalidDateFormat + } + + return Gym.fromImport( + id: uuid, + name: name, + location: location, + supportedClimbTypes: supportedClimbTypes, + difficultySystems: difficultySystems, + customDifficultyGrades: customDifficultyGrades, + notes: notes, + createdAt: createdDate, + updatedAt: updatedDate + ) + } +} + +/// Platform-neutral problem representation for backup/restore +struct BackupProblem: Codable { + let id: String + let gymId: String + let name: String? + let description: String? + let climbType: ClimbType + let difficulty: DifficultyGrade + let tags: [String] + let location: String? + let imagePaths: [String]? + let isActive: Bool + let dateSet: String? // ISO 8601 format + let notes: String? + let createdAt: String // ISO 8601 format + let updatedAt: String // ISO 8601 format + + /// Initialize from native iOS Problem model + init(from problem: Problem) { + self.id = problem.id.uuidString + self.gymId = problem.gymId.uuidString + self.name = problem.name + self.description = problem.description + self.climbType = problem.climbType + self.difficulty = problem.difficulty + self.tags = problem.tags + self.location = problem.location + self.imagePaths = problem.imagePaths.isEmpty ? nil : problem.imagePaths + self.isActive = problem.isActive + self.notes = problem.notes + + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + self.dateSet = problem.dateSet.map { formatter.string(from: $0) } + self.createdAt = formatter.string(from: problem.createdAt) + self.updatedAt = formatter.string(from: problem.updatedAt) + } + + /// Initialize with explicit parameters for import + init( + id: String, + gymId: String, + name: String?, + description: String?, + climbType: ClimbType, + difficulty: DifficultyGrade, + tags: [String] = [], + location: String?, + imagePaths: [String]?, + isActive: Bool, + dateSet: String?, + notes: String?, + createdAt: String, + updatedAt: String + ) { + self.id = id + self.gymId = gymId + self.name = name + self.description = description + self.climbType = climbType + self.difficulty = difficulty + self.tags = tags + self.location = location + self.imagePaths = imagePaths + self.isActive = isActive + self.dateSet = dateSet + self.notes = notes + self.createdAt = createdAt + self.updatedAt = updatedAt + } + + /// Convert to native iOS Problem model + func toProblem() throws -> Problem { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + + guard let uuid = UUID(uuidString: id), + let gymUuid = UUID(uuidString: gymId), + let createdDate = formatter.date(from: createdAt), + let updatedDate = formatter.date(from: updatedAt) + else { + throw BackupError.invalidDateFormat + } + + let dateSetDate = dateSet.flatMap { formatter.date(from: $0) } + + return Problem.fromImport( + id: uuid, + gymId: gymUuid, + name: name, + description: description, + climbType: climbType, + difficulty: difficulty, + tags: tags, + location: location, + imagePaths: imagePaths ?? [], + isActive: isActive, + dateSet: dateSetDate, + notes: notes, + createdAt: createdDate, + updatedAt: updatedDate + ) + } + + /// Create a copy with updated image paths for import processing + func withUpdatedImagePaths(_ newImagePaths: [String]) -> BackupProblem { + return BackupProblem( + id: self.id, + gymId: self.gymId, + name: self.name, + description: self.description, + climbType: self.climbType, + difficulty: self.difficulty, + tags: self.tags, + location: self.location, + imagePaths: newImagePaths.isEmpty ? nil : newImagePaths, + isActive: self.isActive, + dateSet: self.dateSet, + notes: self.notes, + createdAt: self.createdAt, + updatedAt: self.updatedAt + ) + } +} + +/// Platform-neutral climb session representation for backup/restore +struct BackupClimbSession: Codable { + let id: String + let gymId: String + let date: String // ISO 8601 format + let startTime: String? // ISO 8601 format + let endTime: String? // ISO 8601 format + let duration: Int64? // Duration in seconds + let status: SessionStatus + let notes: String? + let createdAt: String // ISO 8601 format + let updatedAt: String // ISO 8601 format + + /// Initialize from native iOS ClimbSession model + init(from session: ClimbSession) { + self.id = session.id.uuidString + self.gymId = session.gymId.uuidString + self.status = session.status + self.notes = session.notes + + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + self.date = formatter.string(from: session.date) + self.startTime = session.startTime.map { formatter.string(from: $0) } + self.endTime = session.endTime.map { formatter.string(from: $0) } + self.duration = session.duration.map { Int64($0) } + self.createdAt = formatter.string(from: session.createdAt) + self.updatedAt = formatter.string(from: session.updatedAt) + } + + /// Initialize with explicit parameters for import + init( + id: String, + gymId: String, + date: String, + startTime: String?, + endTime: String?, + duration: Int64?, + status: SessionStatus, + notes: String?, + createdAt: String, + updatedAt: String + ) { + self.id = id + self.gymId = gymId + self.date = date + self.startTime = startTime + self.endTime = endTime + self.duration = duration + self.status = status + self.notes = notes + self.createdAt = createdAt + self.updatedAt = updatedAt + } + + /// Convert to native iOS ClimbSession model + func toClimbSession() throws -> ClimbSession { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + + guard let uuid = UUID(uuidString: id), + let gymUuid = UUID(uuidString: gymId), + let dateValue = formatter.date(from: date), + let createdDate = formatter.date(from: createdAt), + let updatedDate = formatter.date(from: updatedAt) + else { + throw BackupError.invalidDateFormat + } + + let startTimeValue = startTime.flatMap { formatter.date(from: $0) } + let endTimeValue = endTime.flatMap { formatter.date(from: $0) } + let durationValue = duration.map { Int($0) } + + return ClimbSession.fromImport( + id: uuid, + gymId: gymUuid, + date: dateValue, + startTime: startTimeValue, + endTime: endTimeValue, + duration: durationValue, + status: status, + notes: notes, + createdAt: createdDate, + updatedAt: updatedDate + ) + } +} + +/// Platform-neutral attempt representation for backup/restore +struct BackupAttempt: Codable { + let id: String + let sessionId: String + let problemId: String + let result: AttemptResult + let highestHold: String? + let notes: String? + let duration: Int64? // Duration in seconds + let restTime: Int64? // Rest time in seconds + let timestamp: String // ISO 8601 format + let createdAt: String // ISO 8601 format + + /// Initialize from native iOS Attempt model + init(from attempt: Attempt) { + self.id = attempt.id.uuidString + self.sessionId = attempt.sessionId.uuidString + self.problemId = attempt.problemId.uuidString + self.result = attempt.result + self.highestHold = attempt.highestHold + self.notes = attempt.notes + self.duration = attempt.duration.map { Int64($0) } + self.restTime = attempt.restTime.map { Int64($0) } + + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + self.timestamp = formatter.string(from: attempt.timestamp) + self.createdAt = formatter.string(from: attempt.createdAt) + } + + /// Initialize with explicit parameters for import + init( + id: String, + sessionId: String, + problemId: String, + result: AttemptResult, + highestHold: String?, + notes: String?, + duration: Int64?, + restTime: Int64?, + timestamp: String, + createdAt: String + ) { + self.id = id + self.sessionId = sessionId + self.problemId = problemId + self.result = result + self.highestHold = highestHold + self.notes = notes + self.duration = duration + self.restTime = restTime + self.timestamp = timestamp + self.createdAt = createdAt + } + + /// Convert to native iOS Attempt model + func toAttempt() throws -> Attempt { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] + + guard let uuid = UUID(uuidString: id), + let sessionUuid = UUID(uuidString: sessionId), + let problemUuid = UUID(uuidString: problemId), + let timestampDate = formatter.date(from: timestamp), + let createdDate = formatter.date(from: createdAt) + else { + throw BackupError.invalidDateFormat + } + + let durationValue = duration.map { Int($0) } + let restTimeValue = restTime.map { Int($0) } + + return Attempt.fromImport( + id: uuid, + sessionId: sessionUuid, + problemId: problemUuid, + result: result, + highestHold: highestHold, + notes: notes, + duration: durationValue, + restTime: restTimeValue, + timestamp: timestampDate, + createdAt: createdDate + ) + } +} + +// MARK: - Backup Format Errors + +enum BackupError: LocalizedError { + case invalidDateFormat + case invalidUUID + case missingRequiredField(String) + case unsupportedFormatVersion(String) + + var errorDescription: String? { + switch self { + case .invalidDateFormat: + return "Invalid date format in backup data" + case .invalidUUID: + return "Invalid UUID format in backup data" + case .missingRequiredField(let field): + return "Missing required field: \(field)" + case .unsupportedFormatVersion(let version): + return "Unsupported backup format version: \(version)" + } + } +} + +// MARK: - Extensions + +// MARK: - Helper Extensions for Optional Mapping + +extension Optional { + func map(_ transform: (Wrapped) -> T) -> T? { + return self.flatMap { .some(transform($0)) } + } +} diff --git a/ios/OpenClimb/Utils/ZipUtils.swift b/ios/OpenClimb/Utils/ZipUtils.swift index ebdbd26..64d4fbd 100644 --- a/ios/OpenClimb/Utils/ZipUtils.swift +++ b/ios/OpenClimb/Utils/ZipUtils.swift @@ -1,4 +1,3 @@ - import Compression import Foundation import zlib @@ -10,7 +9,7 @@ struct ZipUtils { private static let METADATA_FILENAME = "metadata.txt" static func createExportZip( - exportData: ClimbDataExport, + exportData: ClimbDataBackup, referencedImagePaths: Set ) throws -> Data { @@ -196,7 +195,7 @@ struct ZipUtils { } private static func createMetadata( - exportData: ClimbDataExport, + exportData: ClimbDataBackup, referencedImagePaths: Set ) -> String { return """ diff --git a/ios/OpenClimb/ViewModels/ClimbingDataManager.swift b/ios/OpenClimb/ViewModels/ClimbingDataManager.swift index 112f549..24719ec 100644 --- a/ios/OpenClimb/ViewModels/ClimbingDataManager.swift +++ b/ios/OpenClimb/ViewModels/ClimbingDataManager.swift @@ -473,13 +473,14 @@ class ClimbingDataManager: ObservableObject { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - let exportData = ClimbDataExport( + let exportData = ClimbDataBackup( exportedAt: dateFormatter.string(from: Date()), version: "2.0", - gyms: gyms.map { AndroidGym(from: $0) }, - problems: problems.map { AndroidProblem(from: $0) }, - sessions: sessions.map { AndroidClimbSession(from: $0) }, - attempts: attempts.map { AndroidAttempt(from: $0) } + formatVersion: "2.0", + gyms: gyms.map { BackupGym(from: $0) }, + problems: problems.map { BackupProblem(from: $0) }, + sessions: sessions.map { BackupClimbSession(from: $0) }, + attempts: attempts.map { BackupAttempt(from: $0) } ) // Collect referenced image paths @@ -529,7 +530,7 @@ class ClimbingDataManager: ObservableObject { print("Raw JSON content preview:") print(String(decoding: importResult.jsonData.prefix(500), as: UTF8.self) + "...") - let importData = try decoder.decode(ClimbDataExport.self, from: importResult.jsonData) + let importData = try decoder.decode(ClimbDataBackup.self, from: importResult.jsonData) print("Successfully decoded import data:") print("- Gyms: \(importData.gyms.count)") @@ -546,10 +547,10 @@ class ClimbingDataManager: ObservableObject { imagePathMapping: importResult.imagePathMapping ) - self.gyms = importData.gyms.map { $0.toGym() } - self.problems = updatedProblems.map { $0.toProblem() } - self.sessions = importData.sessions.map { $0.toClimbSession() } - self.attempts = importData.attempts.map { $0.toAttempt() } + self.gyms = try importData.gyms.map { try $0.toGym() } + self.problems = try updatedProblems.map { try $0.toProblem() } + self.sessions = try importData.sessions.map { try $0.toClimbSession() } + self.attempts = try importData.attempts.map { try $0.toAttempt() } saveGyms() saveProblems() @@ -584,337 +585,6 @@ class ClimbingDataManager: ObservableObject { } } -struct ClimbDataExport: Codable { - let exportedAt: String - let version: String - let gyms: [AndroidGym] - let problems: [AndroidProblem] - let sessions: [AndroidClimbSession] - let attempts: [AndroidAttempt] - - init( - exportedAt: String, version: String = "2.0", gyms: [AndroidGym], problems: [AndroidProblem], - sessions: [AndroidClimbSession], attempts: [AndroidAttempt] - ) { - self.exportedAt = exportedAt - self.version = version - self.gyms = gyms - self.problems = problems - self.sessions = sessions - self.attempts = attempts - } -} - -struct AndroidGym: Codable { - let id: String - let name: String - let location: String? - let supportedClimbTypes: [ClimbType] - let difficultySystems: [DifficultySystem] - let customDifficultyGrades: [String] - let notes: String? - let createdAt: String - let updatedAt: String - - init(from gym: Gym) { - self.id = gym.id.uuidString - self.name = gym.name - self.location = gym.location - self.supportedClimbTypes = gym.supportedClimbTypes - self.difficultySystems = gym.difficultySystems - self.customDifficultyGrades = gym.customDifficultyGrades - self.notes = gym.notes - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - self.createdAt = formatter.string(from: gym.createdAt) - self.updatedAt = formatter.string(from: gym.updatedAt) - } - - init( - id: String, name: String, location: String?, supportedClimbTypes: [ClimbType], - difficultySystems: [DifficultySystem], customDifficultyGrades: [String] = [], - notes: String?, createdAt: String, updatedAt: String - ) { - self.id = id - self.name = name - self.location = location - self.supportedClimbTypes = supportedClimbTypes - self.difficultySystems = difficultySystems - self.customDifficultyGrades = customDifficultyGrades - self.notes = notes - self.createdAt = createdAt - self.updatedAt = updatedAt - } - - func toGym() -> Gym { - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - - let gymId = UUID(uuidString: id) ?? UUID() - let createdDate = formatter.date(from: createdAt) ?? Date() - let updatedDate = formatter.date(from: updatedAt) ?? Date() - - return Gym.fromImport( - id: gymId, - name: name, - location: location, - supportedClimbTypes: supportedClimbTypes, - difficultySystems: difficultySystems, - customDifficultyGrades: customDifficultyGrades, - notes: notes, - createdAt: createdDate, - updatedAt: updatedDate - ) - } -} - -struct AndroidProblem: Codable { - let id: String - let gymId: String - let name: String? - let description: String? - let climbType: ClimbType - let difficulty: DifficultyGrade - let tags: [String] - let location: String? - let imagePaths: [String]? - let isActive: Bool - let dateSet: String? - let notes: String? - let createdAt: String - let updatedAt: String - - init(from problem: Problem) { - self.id = problem.id.uuidString - self.gymId = problem.gymId.uuidString - self.name = problem.name - self.description = problem.description - self.climbType = problem.climbType - self.difficulty = problem.difficulty - self.tags = problem.tags - self.location = problem.location - self.imagePaths = problem.imagePaths.isEmpty ? nil : problem.imagePaths - self.isActive = problem.isActive - self.notes = problem.notes - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - self.dateSet = problem.dateSet != nil ? formatter.string(from: problem.dateSet!) : nil - self.createdAt = formatter.string(from: problem.createdAt) - self.updatedAt = formatter.string(from: problem.updatedAt) - } - - init( - id: String, gymId: String, name: String?, description: String?, climbType: ClimbType, - difficulty: DifficultyGrade, tags: [String] = [], - location: String? = nil, - imagePaths: [String]? = nil, isActive: Bool = true, dateSet: String? = nil, - notes: String? = nil, - createdAt: String, updatedAt: String - ) { - self.id = id - self.gymId = gymId - self.name = name - self.description = description - self.climbType = climbType - self.difficulty = difficulty - self.tags = tags - self.location = location - self.imagePaths = imagePaths - self.isActive = isActive - self.dateSet = dateSet - self.notes = notes - self.createdAt = createdAt - self.updatedAt = updatedAt - } - - func toProblem() -> Problem { - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - - let problemId = UUID(uuidString: id) ?? UUID() - let preservedGymId = UUID(uuidString: gymId) ?? UUID() - let createdDate = formatter.date(from: createdAt) ?? Date() - let updatedDate = formatter.date(from: updatedAt) ?? Date() - - return Problem.fromImport( - id: problemId, - gymId: preservedGymId, - name: name, - description: description, - climbType: climbType, - difficulty: difficulty, - tags: tags, - location: location, - imagePaths: imagePaths ?? [], - isActive: isActive, - dateSet: dateSet != nil ? formatter.date(from: dateSet!) : nil, - notes: notes, - createdAt: createdDate, - updatedAt: updatedDate - ) - } - - func withUpdatedImagePaths(_ newImagePaths: [String]) -> AndroidProblem { - return AndroidProblem( - id: self.id, - gymId: self.gymId, - name: self.name, - description: self.description, - climbType: self.climbType, - difficulty: self.difficulty, - tags: self.tags, - location: self.location, - imagePaths: newImagePaths.isEmpty ? nil : newImagePaths, - isActive: self.isActive, - dateSet: self.dateSet, - notes: self.notes, - createdAt: self.createdAt, - updatedAt: self.updatedAt - ) - } -} - -struct AndroidClimbSession: Codable { - let id: String - let gymId: String - let date: String - let startTime: String? - let endTime: String? - let duration: Int64? - let status: SessionStatus - let notes: String? - let createdAt: String - let updatedAt: String - - init(from session: ClimbSession) { - self.id = session.id.uuidString - self.gymId = session.gymId.uuidString - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - self.date = formatter.string(from: session.date) - self.startTime = session.startTime != nil ? formatter.string(from: session.startTime!) : nil - self.endTime = session.endTime != nil ? formatter.string(from: session.endTime!) : nil - self.duration = session.duration != nil ? Int64(session.duration!) : nil - self.status = session.status - self.notes = session.notes - self.createdAt = formatter.string(from: session.createdAt) - self.updatedAt = formatter.string(from: session.updatedAt) - } - - init( - id: String, gymId: String, date: String, startTime: String?, endTime: String?, - duration: Int64?, status: SessionStatus, notes: String? = nil, createdAt: String, - updatedAt: String - ) { - self.id = id - self.gymId = gymId - self.date = date - self.startTime = startTime - self.endTime = endTime - self.duration = duration - self.status = status - self.notes = notes - self.createdAt = createdAt - self.updatedAt = updatedAt - } - - func toClimbSession() -> ClimbSession { - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - - // Preserve original IDs and dates - let sessionId = UUID(uuidString: id) ?? UUID() - let preservedGymId = UUID(uuidString: gymId) ?? UUID() - let sessionDate = formatter.date(from: date) ?? Date() - let sessionStartTime = startTime != nil ? formatter.date(from: startTime!) : nil - let sessionEndTime = endTime != nil ? formatter.date(from: endTime!) : nil - let createdDate = formatter.date(from: createdAt) ?? Date() - let updatedDate = formatter.date(from: updatedAt) ?? Date() - - return ClimbSession.fromImport( - id: sessionId, - gymId: preservedGymId, - date: sessionDate, - startTime: sessionStartTime, - endTime: sessionEndTime, - duration: duration != nil ? Int(duration!) : nil, - status: status, - notes: notes, - createdAt: createdDate, - updatedAt: updatedDate - ) - } -} - -struct AndroidAttempt: Codable { - let id: String - let sessionId: String - let problemId: String - let result: AttemptResult - let highestHold: String? - let notes: String? - let duration: Int64? - let restTime: Int64? - let timestamp: String - let createdAt: String - - init(from attempt: Attempt) { - self.id = attempt.id.uuidString - self.sessionId = attempt.sessionId.uuidString - self.problemId = attempt.problemId.uuidString - self.result = attempt.result - self.highestHold = attempt.highestHold - self.notes = attempt.notes - self.duration = attempt.duration != nil ? Int64(attempt.duration!) : nil - self.restTime = attempt.restTime != nil ? Int64(attempt.restTime!) : nil - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - self.timestamp = formatter.string(from: attempt.timestamp) - self.createdAt = formatter.string(from: attempt.createdAt) - } - - init( - id: String, sessionId: String, problemId: String, result: AttemptResult, - highestHold: String?, notes: String?, duration: Int64?, restTime: Int64?, - timestamp: String, createdAt: String - ) { - self.id = id - self.sessionId = sessionId - self.problemId = problemId - self.result = result - self.highestHold = highestHold - self.notes = notes - self.duration = duration - self.restTime = restTime - self.timestamp = timestamp - self.createdAt = createdAt - } - - func toAttempt() -> Attempt { - let formatter = DateFormatter() - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS" - - let attemptId = UUID(uuidString: id) ?? UUID() - let preservedSessionId = UUID(uuidString: sessionId) ?? UUID() - let preservedProblemId = UUID(uuidString: problemId) ?? UUID() - let attemptTimestamp = formatter.date(from: timestamp) ?? Date() - let createdDate = formatter.date(from: createdAt) ?? Date() - - return Attempt.fromImport( - id: attemptId, - sessionId: preservedSessionId, - problemId: preservedProblemId, - result: result, - highestHold: highestHold, - notes: notes, - duration: duration != nil ? Int(duration!) : nil, - restTime: restTime != nil ? Int(restTime!) : nil, - timestamp: attemptTimestamp, - createdAt: createdDate - ) - } -} - extension ClimbingDataManager { private func collectReferencedImagePaths() -> Set { var imagePaths = Set() @@ -949,9 +619,9 @@ extension ClimbingDataManager { } private func updateProblemImagePaths( - problems: [AndroidProblem], + problems: [BackupProblem], imagePathMapping: [String: String] - ) -> [AndroidProblem] { + ) -> [BackupProblem] { return problems.map { problem in let updatedImagePaths = (problem.imagePaths ?? []).compactMap { oldPath in let fileName = URL(fileURLWithPath: oldPath).lastPathComponent @@ -1298,7 +968,7 @@ extension ClimbingDataManager { saveAttempts() } - private func validateImportData(_ importData: ClimbDataExport) throws { + private func validateImportData(_ importData: ClimbDataBackup) throws { if importData.gyms.isEmpty { throw NSError( domain: "ImportError", code: 1, diff --git a/ios/OpenClimb/ViewModels/LiveActivityManager.swift b/ios/OpenClimb/ViewModels/LiveActivityManager.swift index c6e7992..4f68042 100644 --- a/ios/OpenClimb/ViewModels/LiveActivityManager.swift +++ b/ios/OpenClimb/ViewModels/LiveActivityManager.swift @@ -130,14 +130,8 @@ final class LiveActivityManager { completedProblems: completedProblems ) - do { - await currentActivity.update(.init(state: updatedContentState, staleDate: nil)) - print("✅ Live Activity updated successfully") - } catch { - print("❌ Failed to update Live Activity: \(error)") - // If update fails, the activity might have been dismissed - self.currentActivity = nil - } + await currentActivity.update(.init(state: updatedContentState, staleDate: nil)) + print("✅ Live Activity updated successfully") } /// Call this when a ClimbSession ends to end the Live Activity diff --git a/ios/OpenClimb/Views/SessionsView.swift b/ios/OpenClimb/Views/SessionsView.swift index a9df99b..0d759d3 100644 --- a/ios/OpenClimb/Views/SessionsView.swift +++ b/ios/OpenClimb/Views/SessionsView.swift @@ -168,15 +168,9 @@ struct ActiveSessionBanner: View { .onDisappear { stopTimer() } - .background( - NavigationLink( - destination: SessionDetailView(sessionId: session.id), - isActive: $navigateToDetail - ) { - EmptyView() - } - .hidden() - ) + .navigationDestination(isPresented: $navigateToDetail) { + SessionDetailView(sessionId: session.id) + } } private func formatDuration(from start: Date, to end: Date) -> String {