diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2fe5c30..1389566 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,4 +1,4 @@ -name: OpenClimb Docker Deploy +name: Ascently Docker Deploy on: push: branches: [main] @@ -34,5 +34,5 @@ jobs: platforms: linux/amd64 push: true tags: | - ${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/openclimb-sync:${{ github.sha }} - ${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/openclimb-sync:latest + ${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/ascently-sync:${{ github.sha }} + ${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/ascently-sync:latest diff --git a/README.md b/README.md index 575fc02..caece1a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# OpenClimb +# Ascently This is a FOSS app meant to help climbers track their sessions, routes/problems, and overall progress. This app is offline-only and requires no special permissions to run. Its built using Jetpack Compose with Material You support on Android and SwiftUI on iOS. @@ -7,7 +7,7 @@ This is a FOSS app meant to help climbers track their sessions, routes/problems, For Android do one of the following: 1. Download the latest APK from the Releases page -2. [Obtainium](https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/%7B%22id%22%3A%22com.atridad.openclimb%22%2C%22url%22%3A%22https%3A%2F%2Fgit.atri.dad%2Fatridad%2FOpenClimb%2Freleases%22%2C%22author%22%3A%22git.atri.dad%22%2C%22name%22%3A%22OpenClimb%22%2C%22preferredApkIndex%22%3A0%2C%22additionalSettings%22%3A%22%7B%5C%22intermediateLink%5C%22%3A%5B%5D%2C%5C%22customLinkFilterRegex%5C%22%3A%5C%22%5C%22%2C%5C%22filterByLinkText%5C%22%3Afalse%2C%5C%22skipSort%5C%22%3Afalse%2C%5C%22reverseSort%5C%22%3Afalse%2C%5C%22sortByLastLinkSegment%5C%22%3Afalse%2C%5C%22versionExtractWholePage%5C%22%3Afalse%2C%5C%22requestHeader%5C%22%3A%5B%7B%5C%22requestHeader%5C%22%3A%5C%22User-Agent%3A%20Mozilla%2F5.0%20(Linux%3B%20Android%2010%3B%20K)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F114.0.0.0%20Mobile%20Safari%2F537.36%5C%22%7D%5D%2C%5C%22defaultPseudoVersioningMethod%5C%22%3A%5C%22partialAPKHash%5C%22%2C%5C%22trackOnly%5C%22%3Afalse%2C%5C%22versionExtractionRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22matchGroupToUse%5C%22%3A%5C%22%5C%22%2C%5C%22versionDetection%5C%22%3Afalse%2C%5C%22useVersionCodeAsOSVersion%5C%22%3Afalse%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22invertAPKFilter%5C%22%3Afalse%2C%5C%22autoApkFilterByArch%5C%22%3Atrue%2C%5C%22appName%5C%22%3A%5C%22OpenClimb%5C%22%2C%5C%22appAuthor%5C%22%3A%5C%22%5C%22%2C%5C%22shizukuPretendToBeGooglePlay%5C%22%3Afalse%2C%5C%22allowInsecure%5C%22%3Afalse%2C%5C%22exemptFromBackgroundUpdates%5C%22%3Afalse%2C%5C%22skipUpdateNotifications%5C%22%3Afalse%2C%5C%22about%5C%22%3A%5C%22%5C%22%2C%5C%22refreshBeforeDownload%5C%22%3Afalse%7D%22%2C%22overrideSource%22%3Anull%7D) +2. [Obtainium](https://apps.obtainium.imranr.dev/redirect?r=obtainium://app/%7B%22id%22%3A%22com.atridad.ascently%22%2C%22url%22%3A%22https%3A%2F%2Fgit.atri.dad%2Fatridad%2FAscently%2Freleases%22%2C%22author%22%3A%22git.atri.dad%22%2C%22name%22%3A%22Ascently%22%2C%22preferredApkIndex%22%3A0%2C%22additionalSettings%22%3A%22%7B%5C%22intermediateLink%5C%22%3A%5B%5D%2C%5C%22customLinkFilterRegex%5C%22%3A%5C%22%5C%22%2C%5C%22filterByLinkText%5C%22%3Afalse%2C%5C%22skipSort%5C%22%3Afalse%2C%5C%22reverseSort%5C%22%3Afalse%2C%5C%22sortByLastLinkSegment%5C%22%3Afalse%2C%5C%22versionExtractWholePage%5C%22%3Afalse%2C%5C%22requestHeader%5C%22%3A%5B%7B%5C%22requestHeader%5C%22%3A%5C%22User-Agent%3A%20Mozilla%2F5.0%20(Linux%3B%20Android%2010%3B%20K)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F114.0.0.0%20Mobile%20Safari%2F537.36%5C%22%7D%5D%2C%5C%22defaultPseudoVersioningMethod%5C%22%3A%5C%22partialAPKHash%5C%22%2C%5C%22trackOnly%5C%22%3Afalse%2C%5C%22versionExtractionRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22matchGroupToUse%5C%22%3A%5C%22%5C%22%2C%5C%22versionDetection%5C%22%3Afalse%2C%5C%22useVersionCodeAsOSVersion%5C%22%3Afalse%2C%5C%22apkFilterRegEx%5C%22%3A%5C%22%5C%22%2C%5C%22invertAPKFilter%5C%22%3Afalse%2C%5C%22autoApkFilterByArch%5C%22%3Atrue%2C%5C%22appName%5C%22%3A%5C%22Ascently%5C%22%2C%5C%22appAuthor%5C%22%3A%5C%22%5C%22%2C%5C%22shizukuPretendToBeGooglePlay%5C%22%3Afalse%2C%5C%22allowInsecure%5C%22%3Afalse%2C%5C%22exemptFromBackgroundUpdates%5C%22%3Afalse%2C%5C%22skipUpdateNotifications%5C%22%3Afalse%2C%5C%22about%5C%22%3A%5C%22%5C%22%2C%5C%22refreshBeforeDownload%5C%22%3Afalse%7D%22%2C%22overrideSource%22%3Anull%7D) For iOS: @@ -22,12 +22,12 @@ You can run your own sync server to keep your data in sync across devices. The s 1. Create a `.env` file with your configuration: ``` -IMAGE=git.atri.dad/atridad/openclimb-sync:latest +IMAGE=git.atri.dad/atridad/ascently-sync:latest APP_PORT=8080 AUTH_TOKEN=your-secure-auth-token-here -DATA_FILE=/data/openclimb.json +DATA_FILE=/data/ascently.json IMAGES_DIR=/data/images -ROOT_DIR=./openclimb-data +ROOT_DIR=./ascently-data ``` 2. Use the provided `docker-compose.yml` in the `sync/` directory: diff --git a/android/README.md b/android/README.md index 1944898..e18053f 100644 --- a/android/README.md +++ b/android/README.md @@ -1,10 +1,10 @@ -# OpenClimb for Android +# Ascently for Android -This is the native Android app for OpenClimb, built with Kotlin and Jetpack Compose. +This is the native Android app for Ascently, built with Kotlin and Jetpack Compose. ## Project Structure -This is a standard Android Gradle project. The main code lives in `app/src/main/java/com/atridad/openclimb/`. +This is a standard Android Gradle project. The main code lives in `app/src/main/java/com/atridad/ascently/`. - `data/`: Handles all the app's data. - `database/`: Room database setup (DAOs, entities). diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index acecb41..34bf92b 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -9,11 +9,11 @@ plugins { } android { - namespace = "com.atridad.openclimb" + namespace = "com.atridad.ascently" compileSdk = 36 defaultConfig { - applicationId = "com.atridad.openclimb" + applicationId = "com.atridad.ascently" minSdk = 31 targetSdk = 36 versionCode = 39 diff --git a/android/app/build.gradle.kts.backup b/android/app/build.gradle.kts.backup index 3d33435..8721e3c 100644 --- a/android/app/build.gradle.kts.backup +++ b/android/app/build.gradle.kts.backup @@ -9,11 +9,11 @@ plugins { } android { - namespace = "com.atridad.openclimb" + namespace = "com.atridad.ascently" compileSdk = 36 defaultConfig { - applicationId = "com.atridad.openclimb" + applicationId = "com.atridad.ascently" minSdk = 31 targetSdk = 36 versionCode = 27 diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 52b0e91..1d0ffa4 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -50,13 +50,13 @@ android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" - android:theme="@style/Theme.OpenClimb" + android:theme="@style/Theme.Ascently" tools:targetApi="31"> + android:theme="@style/Theme.Ascently.Splash"> diff --git a/android/app/src/main/java/com/atridad/openclimb/MainActivity.kt b/android/app/src/main/java/com/atridad/ascently/MainActivity.kt similarity index 78% rename from android/app/src/main/java/com/atridad/openclimb/MainActivity.kt rename to android/app/src/main/java/com/atridad/ascently/MainActivity.kt index 928a51f..7f66490 100644 --- a/android/app/src/main/java/com/atridad/openclimb/MainActivity.kt +++ b/android/app/src/main/java/com/atridad/ascently/MainActivity.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb +package com.atridad.ascently import android.content.Intent import android.os.Bundle @@ -9,8 +9,9 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import com.atridad.openclimb.ui.OpenClimbApp -import com.atridad.openclimb.ui.theme.OpenClimbTheme +import com.atridad.ascently.ui.AscentlyApp +import com.atridad.ascently.ui.theme.AscentlyTheme +import com.atridad.ascently.utils.MigrationManager class MainActivity : ComponentActivity() { private var shortcutAction by mutableStateOf(null) @@ -23,16 +24,19 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setTheme(R.style.Theme_OpenClimb) + setTheme(R.style.Theme_Ascently) enableEdgeToEdge() + // Perform migration from OpenClimb to Ascently if needed + MigrationManager(this).migrateIfNeeded() + shortcutAction = intent?.action lastUsedGymId = intent?.getStringExtra("LAST_USED_GYM_ID") setContent { - OpenClimbTheme { + AscentlyTheme { Surface(modifier = Modifier.fillMaxSize()) { - OpenClimbApp( + AscentlyApp( shortcutAction = shortcutAction, lastUsedGymId = lastUsedGymId, onShortcutActionProcessed = { clearShortcutAction() } diff --git a/android/app/src/main/java/com/atridad/openclimb/data/database/Converters.kt b/android/app/src/main/java/com/atridad/ascently/data/database/Converters.kt similarity index 95% rename from android/app/src/main/java/com/atridad/openclimb/data/database/Converters.kt rename to android/app/src/main/java/com/atridad/ascently/data/database/Converters.kt index 8ab3cba..8bcd29e 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/database/Converters.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/database/Converters.kt @@ -1,7 +1,7 @@ -package com.atridad.openclimb.data.database +package com.atridad.ascently.data.database import androidx.room.TypeConverter -import com.atridad.openclimb.data.model.* +import com.atridad.ascently.data.model.* import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json diff --git a/android/app/src/main/java/com/atridad/openclimb/data/database/OpenClimbDatabase.kt b/android/app/src/main/java/com/atridad/ascently/data/database/OpenClimbDatabase.kt similarity index 90% rename from android/app/src/main/java/com/atridad/openclimb/data/database/OpenClimbDatabase.kt rename to android/app/src/main/java/com/atridad/ascently/data/database/OpenClimbDatabase.kt index 852988b..6f5fa36 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/database/OpenClimbDatabase.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/database/OpenClimbDatabase.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.data.database +package com.atridad.ascently.data.database import android.content.Context import androidx.room.Database @@ -7,8 +7,8 @@ import androidx.room.RoomDatabase import androidx.room.TypeConverters import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase -import com.atridad.openclimb.data.database.dao.* -import com.atridad.openclimb.data.model.* +import com.atridad.ascently.data.database.dao.* +import com.atridad.ascently.data.model.* @Database( entities = [Gym::class, Problem::class, ClimbSession::class, Attempt::class], @@ -16,7 +16,7 @@ import com.atridad.openclimb.data.model.* exportSchema = false ) @TypeConverters(Converters::class) -abstract class OpenClimbDatabase : RoomDatabase() { +abstract class AscentlyDatabase : RoomDatabase() { abstract fun gymDao(): GymDao abstract fun problemDao(): ProblemDao @@ -24,7 +24,7 @@ abstract class OpenClimbDatabase : RoomDatabase() { abstract fun attemptDao(): AttemptDao companion object { - @Volatile private var INSTANCE: OpenClimbDatabase? = null + @Volatile private var INSTANCE: AscentlyDatabase? = null val MIGRATION_4_5 = object : Migration(4, 5) { @@ -84,14 +84,14 @@ abstract class OpenClimbDatabase : RoomDatabase() { } } - fun getDatabase(context: Context): OpenClimbDatabase { + fun getDatabase(context: Context): AscentlyDatabase { return INSTANCE ?: synchronized(this) { val instance = Room.databaseBuilder( context.applicationContext, - OpenClimbDatabase::class.java, - "openclimb_database" + AscentlyDatabase::class.java, + "ascently_database" ) .addMigrations(MIGRATION_4_5, MIGRATION_5_6) .enableMultiInstanceInvalidation() diff --git a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/AttemptDao.kt b/android/app/src/main/java/com/atridad/ascently/data/database/dao/AttemptDao.kt similarity index 95% rename from android/app/src/main/java/com/atridad/openclimb/data/database/dao/AttemptDao.kt rename to android/app/src/main/java/com/atridad/ascently/data/database/dao/AttemptDao.kt index 75adde1..4d86b68 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/AttemptDao.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/database/dao/AttemptDao.kt @@ -1,8 +1,8 @@ -package com.atridad.openclimb.data.database.dao +package com.atridad.ascently.data.database.dao import androidx.room.* -import com.atridad.openclimb.data.model.Attempt -import com.atridad.openclimb.data.model.AttemptResult +import com.atridad.ascently.data.model.Attempt +import com.atridad.ascently.data.model.AttemptResult import kotlinx.coroutines.flow.Flow @Dao diff --git a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/ClimbSessionDao.kt b/android/app/src/main/java/com/atridad/ascently/data/database/dao/ClimbSessionDao.kt similarity index 94% rename from android/app/src/main/java/com/atridad/openclimb/data/database/dao/ClimbSessionDao.kt rename to android/app/src/main/java/com/atridad/ascently/data/database/dao/ClimbSessionDao.kt index f42920d..452b3c9 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/ClimbSessionDao.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/database/dao/ClimbSessionDao.kt @@ -1,8 +1,8 @@ -package com.atridad.openclimb.data.database.dao +package com.atridad.ascently.data.database.dao import androidx.room.* -import com.atridad.openclimb.data.model.ClimbSession -import com.atridad.openclimb.data.model.SessionStatus +import com.atridad.ascently.data.model.ClimbSession +import com.atridad.ascently.data.model.SessionStatus import kotlinx.coroutines.flow.Flow @Dao diff --git a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/GymDao.kt b/android/app/src/main/java/com/atridad/ascently/data/database/dao/GymDao.kt similarity index 89% rename from android/app/src/main/java/com/atridad/openclimb/data/database/dao/GymDao.kt rename to android/app/src/main/java/com/atridad/ascently/data/database/dao/GymDao.kt index 3bc9a81..045ee54 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/GymDao.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/database/dao/GymDao.kt @@ -1,8 +1,8 @@ -package com.atridad.openclimb.data.database.dao +package com.atridad.ascently.data.database.dao import androidx.room.* -import com.atridad.openclimb.data.model.ClimbType -import com.atridad.openclimb.data.model.Gym +import com.atridad.ascently.data.model.ClimbType +import com.atridad.ascently.data.model.Gym import kotlinx.coroutines.flow.Flow @Dao diff --git a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/ProblemDao.kt b/android/app/src/main/java/com/atridad/ascently/data/database/dao/ProblemDao.kt similarity index 93% rename from android/app/src/main/java/com/atridad/openclimb/data/database/dao/ProblemDao.kt rename to android/app/src/main/java/com/atridad/ascently/data/database/dao/ProblemDao.kt index 6546258..5529e11 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/database/dao/ProblemDao.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/database/dao/ProblemDao.kt @@ -1,8 +1,8 @@ -package com.atridad.openclimb.data.database.dao +package com.atridad.ascently.data.database.dao import androidx.room.* -import com.atridad.openclimb.data.model.ClimbType -import com.atridad.openclimb.data.model.Problem +import com.atridad.ascently.data.model.ClimbType +import com.atridad.ascently.data.model.Problem import kotlinx.coroutines.flow.Flow @Dao diff --git a/android/app/src/main/java/com/atridad/openclimb/data/format/BackupFormat.kt b/android/app/src/main/java/com/atridad/ascently/data/format/BackupFormat.kt similarity index 98% rename from android/app/src/main/java/com/atridad/openclimb/data/format/BackupFormat.kt rename to android/app/src/main/java/com/atridad/ascently/data/format/BackupFormat.kt index fc3299c..2d96088 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/format/BackupFormat.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/format/BackupFormat.kt @@ -1,9 +1,9 @@ -package com.atridad.openclimb.data.format +package com.atridad.ascently.data.format -import com.atridad.openclimb.data.model.* +import com.atridad.ascently.data.model.* import kotlinx.serialization.Serializable -// Root structure for OpenClimb backup data +// Root structure for Ascently backup data @Serializable data class ClimbDataBackup( val exportedAt: String, diff --git a/android/app/src/main/java/com/atridad/openclimb/data/health/HealthConnectStub.kt b/android/app/src/main/java/com/atridad/ascently/data/health/HealthConnectStub.kt similarity index 98% rename from android/app/src/main/java/com/atridad/openclimb/data/health/HealthConnectStub.kt rename to android/app/src/main/java/com/atridad/ascently/data/health/HealthConnectStub.kt index a2500be..a8ce0e2 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/health/HealthConnectStub.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/health/HealthConnectStub.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.data.health +package com.atridad.ascently.data.health import android.annotation.SuppressLint import android.content.Context @@ -12,9 +12,9 @@ import androidx.health.connect.client.records.ExerciseSessionRecord import androidx.health.connect.client.records.HeartRateRecord import androidx.health.connect.client.records.TotalCaloriesBurnedRecord import androidx.health.connect.client.units.Energy -import com.atridad.openclimb.data.model.ClimbSession -import com.atridad.openclimb.data.model.SessionStatus -import com.atridad.openclimb.utils.DateFormatUtils +import com.atridad.ascently.data.model.ClimbSession +import com.atridad.ascently.data.model.SessionStatus +import com.atridad.ascently.utils.DateFormatUtils import java.time.Duration import java.time.Instant import java.time.ZoneOffset @@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.flow /** - * Health Connect manager for OpenClimb that syncs climbing sessions to Samsung Health, Google Fit, + * Health Connect manager for Ascently that syncs climbing sessions to Samsung Health, Google Fit, * and other health apps. */ @SuppressLint("RestrictedApi") @@ -192,7 +192,7 @@ class HealthConnectManager(private val context: Context) { } else { results.add("❌ Health Connect not ready") if (!available) results.add("- Health Connect not available on device") - if (!_isEnabled.value) results.add("- Not enabled in OpenClimb settings") + if (!_isEnabled.value) results.add("- Not enabled in Ascently settings") if (!hasPerms) results.add("- Permissions not granted") if (!_isCompatible.value) results.add("- API compatibility issues") } diff --git a/android/app/src/main/java/com/atridad/openclimb/data/model/Attempt.kt b/android/app/src/main/java/com/atridad/ascently/data/model/Attempt.kt similarity index 96% rename from android/app/src/main/java/com/atridad/openclimb/data/model/Attempt.kt rename to android/app/src/main/java/com/atridad/ascently/data/model/Attempt.kt index 92d4e57..4951e7d 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/model/Attempt.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/model/Attempt.kt @@ -1,10 +1,10 @@ -package com.atridad.openclimb.data.model +package com.atridad.ascently.data.model import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index import androidx.room.PrimaryKey -import com.atridad.openclimb.utils.DateFormatUtils +import com.atridad.ascently.utils.DateFormatUtils import kotlinx.serialization.Serializable @Serializable diff --git a/android/app/src/main/java/com/atridad/openclimb/data/model/ClimbSession.kt b/android/app/src/main/java/com/atridad/ascently/data/model/ClimbSession.kt similarity index 96% rename from android/app/src/main/java/com/atridad/openclimb/data/model/ClimbSession.kt rename to android/app/src/main/java/com/atridad/ascently/data/model/ClimbSession.kt index 0c4b5c9..af1e026 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/model/ClimbSession.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/model/ClimbSession.kt @@ -1,10 +1,10 @@ -package com.atridad.openclimb.data.model +package com.atridad.ascently.data.model import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index import androidx.room.PrimaryKey -import com.atridad.openclimb.utils.DateFormatUtils +import com.atridad.ascently.utils.DateFormatUtils import kotlinx.serialization.Serializable @Serializable diff --git a/android/app/src/main/java/com/atridad/openclimb/data/model/ClimbType.kt b/android/app/src/main/java/com/atridad/ascently/data/model/ClimbType.kt similarity index 86% rename from android/app/src/main/java/com/atridad/openclimb/data/model/ClimbType.kt rename to android/app/src/main/java/com/atridad/ascently/data/model/ClimbType.kt index 8647cee..841f89a 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/model/ClimbType.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/model/ClimbType.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.data.model +package com.atridad.ascently.data.model import kotlinx.serialization.Serializable diff --git a/android/app/src/main/java/com/atridad/openclimb/data/model/DifficultySystem.kt b/android/app/src/main/java/com/atridad/ascently/data/model/DifficultySystem.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/data/model/DifficultySystem.kt rename to android/app/src/main/java/com/atridad/ascently/data/model/DifficultySystem.kt index 39da548..8750109 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/model/DifficultySystem.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/model/DifficultySystem.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.data.model +package com.atridad.ascently.data.model import kotlinx.serialization.Serializable diff --git a/android/app/src/main/java/com/atridad/openclimb/data/model/Gym.kt b/android/app/src/main/java/com/atridad/ascently/data/model/Gym.kt similarity index 93% rename from android/app/src/main/java/com/atridad/openclimb/data/model/Gym.kt rename to android/app/src/main/java/com/atridad/ascently/data/model/Gym.kt index 1876cd9..c1670a4 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/model/Gym.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/model/Gym.kt @@ -1,8 +1,8 @@ -package com.atridad.openclimb.data.model +package com.atridad.ascently.data.model import androidx.room.Entity import androidx.room.PrimaryKey -import com.atridad.openclimb.utils.DateFormatUtils +import com.atridad.ascently.utils.DateFormatUtils import kotlinx.serialization.Serializable @Entity(tableName = "gyms") diff --git a/android/app/src/main/java/com/atridad/openclimb/data/model/Problem.kt b/android/app/src/main/java/com/atridad/ascently/data/model/Problem.kt similarity index 96% rename from android/app/src/main/java/com/atridad/openclimb/data/model/Problem.kt rename to android/app/src/main/java/com/atridad/ascently/data/model/Problem.kt index b983d22..2d3aa82 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/model/Problem.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/model/Problem.kt @@ -1,10 +1,10 @@ -package com.atridad.openclimb.data.model +package com.atridad.ascently.data.model import androidx.room.Entity import androidx.room.ForeignKey import androidx.room.Index import androidx.room.PrimaryKey -import com.atridad.openclimb.utils.DateFormatUtils +import com.atridad.ascently.utils.DateFormatUtils import kotlinx.serialization.Serializable @Entity( diff --git a/android/app/src/main/java/com/atridad/openclimb/data/repository/ClimbRepository.kt b/android/app/src/main/java/com/atridad/ascently/data/repository/ClimbRepository.kt similarity index 94% rename from android/app/src/main/java/com/atridad/openclimb/data/repository/ClimbRepository.kt rename to android/app/src/main/java/com/atridad/ascently/data/repository/ClimbRepository.kt index f028bae..6d8260c 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/repository/ClimbRepository.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/repository/ClimbRepository.kt @@ -1,25 +1,25 @@ -package com.atridad.openclimb.data.repository +package com.atridad.ascently.data.repository import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -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.format.DeletedItem -import com.atridad.openclimb.data.model.* -import com.atridad.openclimb.data.state.DataStateManager -import com.atridad.openclimb.utils.DateFormatUtils -import com.atridad.openclimb.utils.ZipExportImportUtils +import com.atridad.ascently.data.database.AscentlyDatabase +import com.atridad.ascently.data.format.BackupAttempt +import com.atridad.ascently.data.format.BackupClimbSession +import com.atridad.ascently.data.format.BackupGym +import com.atridad.ascently.data.format.BackupProblem +import com.atridad.ascently.data.format.ClimbDataBackup +import com.atridad.ascently.data.format.DeletedItem +import com.atridad.ascently.data.model.* +import com.atridad.ascently.data.state.DataStateManager +import com.atridad.ascently.utils.DateFormatUtils +import com.atridad.ascently.utils.ZipExportImportUtils import java.io.File import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.first import kotlinx.serialization.json.Json -class ClimbRepository(database: OpenClimbDatabase, private val context: Context) { +class ClimbRepository(database: AscentlyDatabase, private val context: Context) { private val gymDao = database.gymDao() private val problemDao = database.problemDao() private val sessionDao = database.climbSessionDao() @@ -157,7 +157,7 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context) .filter { imagePath -> try { val imageFile = - com.atridad.openclimb.utils.ImageUtils.getImageFile( + com.atridad.ascently.utils.ImageUtils.getImageFile( context, imagePath ) diff --git a/android/app/src/main/java/com/atridad/openclimb/data/state/DataStateManager.kt b/android/app/src/main/java/com/atridad/ascently/data/state/DataStateManager.kt similarity index 92% rename from android/app/src/main/java/com/atridad/openclimb/data/state/DataStateManager.kt rename to android/app/src/main/java/com/atridad/ascently/data/state/DataStateManager.kt index 85064c4..32ae8fb 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/state/DataStateManager.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/state/DataStateManager.kt @@ -1,10 +1,10 @@ -package com.atridad.openclimb.data.state +package com.atridad.ascently.data.state import android.content.Context import android.content.SharedPreferences import android.util.Log -import com.atridad.openclimb.utils.DateFormatUtils import androidx.core.content.edit +import com.atridad.ascently.utils.DateFormatUtils /** * Manages the overall data state timestamp for sync purposes. This tracks when any data in the @@ -14,7 +14,7 @@ class DataStateManager(context: Context) { companion object { private const val TAG = "DataStateManager" - private const val PREFS_NAME = "openclimb_data_state" + private const val PREFS_NAME = "ascently_data_state" private const val KEY_LAST_MODIFIED = "last_modified_timestamp" private const val KEY_INITIALIZED = "state_initialized" } @@ -58,5 +58,4 @@ class DataStateManager(context: Context) { private fun markAsInitialized() { prefs.edit { putBoolean(KEY_INITIALIZED, true) } } - } diff --git a/android/app/src/main/java/com/atridad/openclimb/data/sync/SyncService.kt b/android/app/src/main/java/com/atridad/ascently/data/sync/SyncService.kt similarity index 97% rename from android/app/src/main/java/com/atridad/openclimb/data/sync/SyncService.kt rename to android/app/src/main/java/com/atridad/ascently/data/sync/SyncService.kt index 9aac55b..cae5434 100644 --- a/android/app/src/main/java/com/atridad/openclimb/data/sync/SyncService.kt +++ b/android/app/src/main/java/com/atridad/ascently/data/sync/SyncService.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.data.sync +package com.atridad.ascently.data.sync import android.content.Context import android.content.SharedPreferences @@ -7,16 +7,16 @@ import android.net.NetworkCapabilities import android.util.Log import androidx.annotation.RequiresPermission import androidx.core.content.edit -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.repository.ClimbRepository -import com.atridad.openclimb.data.state.DataStateManager -import com.atridad.openclimb.utils.DateFormatUtils -import com.atridad.openclimb.utils.ImageNamingUtils -import com.atridad.openclimb.utils.ImageUtils +import com.atridad.ascently.data.format.BackupAttempt +import com.atridad.ascently.data.format.BackupClimbSession +import com.atridad.ascently.data.format.BackupGym +import com.atridad.ascently.data.format.BackupProblem +import com.atridad.ascently.data.format.ClimbDataBackup +import com.atridad.ascently.data.repository.ClimbRepository +import com.atridad.ascently.data.state.DataStateManager +import com.atridad.ascently.utils.DateFormatUtils +import com.atridad.ascently.utils.ImageNamingUtils +import com.atridad.ascently.utils.ImageUtils import java.io.IOException import java.io.Serializable import java.util.concurrent.TimeUnit diff --git a/android/app/src/main/java/com/atridad/openclimb/navigation/BottomNavigationItem.kt b/android/app/src/main/java/com/atridad/ascently/navigation/BottomNavigationItem.kt similarity index 96% rename from android/app/src/main/java/com/atridad/openclimb/navigation/BottomNavigationItem.kt rename to android/app/src/main/java/com/atridad/ascently/navigation/BottomNavigationItem.kt index a966854..2a223c3 100644 --- a/android/app/src/main/java/com/atridad/openclimb/navigation/BottomNavigationItem.kt +++ b/android/app/src/main/java/com/atridad/ascently/navigation/BottomNavigationItem.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.navigation +package com.atridad.ascently.navigation import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* diff --git a/android/app/src/main/java/com/atridad/openclimb/navigation/Screen.kt b/android/app/src/main/java/com/atridad/ascently/navigation/Screen.kt similarity index 95% rename from android/app/src/main/java/com/atridad/openclimb/navigation/Screen.kt rename to android/app/src/main/java/com/atridad/ascently/navigation/Screen.kt index c459e07..f56fbfd 100644 --- a/android/app/src/main/java/com/atridad/openclimb/navigation/Screen.kt +++ b/android/app/src/main/java/com/atridad/ascently/navigation/Screen.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.navigation +package com.atridad.ascently.navigation import kotlinx.serialization.Serializable diff --git a/android/app/src/main/java/com/atridad/openclimb/service/SessionTrackingService.kt b/android/app/src/main/java/com/atridad/ascently/service/SessionTrackingService.kt similarity index 94% rename from android/app/src/main/java/com/atridad/openclimb/service/SessionTrackingService.kt rename to android/app/src/main/java/com/atridad/ascently/service/SessionTrackingService.kt index 091d45c..a4734b1 100644 --- a/android/app/src/main/java/com/atridad/openclimb/service/SessionTrackingService.kt +++ b/android/app/src/main/java/com/atridad/ascently/service/SessionTrackingService.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.service +package com.atridad.ascently.service import android.app.NotificationChannel import android.app.NotificationManager @@ -8,10 +8,10 @@ import android.content.Context import android.content.Intent import android.os.IBinder import androidx.core.app.NotificationCompat -import com.atridad.openclimb.MainActivity -import com.atridad.openclimb.R -import com.atridad.openclimb.data.database.OpenClimbDatabase -import com.atridad.openclimb.data.repository.ClimbRepository +import com.atridad.ascently.MainActivity +import com.atridad.ascently.R +import com.atridad.ascently.data.database.AscentlyDatabase +import com.atridad.ascently.data.repository.ClimbRepository import kotlinx.coroutines.* import kotlinx.coroutines.flow.firstOrNull import java.time.LocalDateTime @@ -52,7 +52,7 @@ class SessionTrackingService : Service() { override fun onCreate() { super.onCreate() - val database = OpenClimbDatabase.getDatabase(this) + val database = AscentlyDatabase.getDatabase(this) repository = ClimbRepository(database, this) notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager @@ -75,8 +75,8 @@ class SessionTrackingService : Service() { sessionId != null -> repository.getSessionById(sessionId) else -> repository.getActiveSession() } - if (targetSession != null && targetSession.status == com.atridad.openclimb.data.model.SessionStatus.ACTIVE) { - val completed = with(com.atridad.openclimb.data.model.ClimbSession) { targetSession.complete() } + if (targetSession != null && targetSession.status == com.atridad.ascently.data.model.SessionStatus.ACTIVE) { + val completed = with(com.atridad.ascently.data.model.ClimbSession) { targetSession.complete() } repository.updateSession(completed) } } finally { @@ -127,7 +127,7 @@ class SessionTrackingService : Service() { } val session = repository.getSessionById(sessionId) - if (session == null || session.status != com.atridad.openclimb.data.model.SessionStatus.ACTIVE) { + if (session == null || session.status != com.atridad.ascently.data.model.SessionStatus.ACTIVE) { stopSessionTracking() break } @@ -175,7 +175,7 @@ class SessionTrackingService : Service() { val session = runBlocking { repository.getSessionById(sessionId) } - if (session == null || session.status != com.atridad.openclimb.data.model.SessionStatus.ACTIVE) { + if (session == null || session.status != com.atridad.ascently.data.model.SessionStatus.ACTIVE) { stopSessionTracking() return } diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/OpenClimbApp.kt b/android/app/src/main/java/com/atridad/ascently/ui/AscentlyApp.kt similarity index 92% rename from android/app/src/main/java/com/atridad/openclimb/ui/OpenClimbApp.kt rename to android/app/src/main/java/com/atridad/ascently/ui/AscentlyApp.kt index f2b4778..a26a88e 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/OpenClimbApp.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/AscentlyApp.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui +package com.atridad.ascently.ui import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -17,21 +17,21 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.toRoute -import com.atridad.openclimb.data.database.OpenClimbDatabase -import com.atridad.openclimb.data.repository.ClimbRepository -import com.atridad.openclimb.data.sync.SyncService -import com.atridad.openclimb.navigation.Screen -import com.atridad.openclimb.navigation.bottomNavigationItems -import com.atridad.openclimb.ui.components.NotificationPermissionDialog -import com.atridad.openclimb.ui.screens.* -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel -import com.atridad.openclimb.ui.viewmodel.ClimbViewModelFactory -import com.atridad.openclimb.utils.AppShortcutManager -import com.atridad.openclimb.utils.NotificationPermissionUtils +import com.atridad.ascently.data.database.AscentlyDatabase +import com.atridad.ascently.data.repository.ClimbRepository +import com.atridad.ascently.data.sync.SyncService +import com.atridad.ascently.navigation.Screen +import com.atridad.ascently.navigation.bottomNavigationItems +import com.atridad.ascently.ui.components.NotificationPermissionDialog +import com.atridad.ascently.ui.screens.* +import com.atridad.ascently.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.ui.viewmodel.ClimbViewModelFactory +import com.atridad.ascently.utils.AppShortcutManager +import com.atridad.ascently.utils.NotificationPermissionUtils @OptIn(ExperimentalMaterial3Api::class) @Composable -fun OpenClimbApp( +fun AscentlyApp( shortcutAction: String? = null, lastUsedGymId: String? = null, onShortcutActionProcessed: () -> Unit = {} @@ -39,9 +39,9 @@ fun OpenClimbApp( val navController = rememberNavController() val context = LocalContext.current - var lastUsedGym by remember { mutableStateOf(null) } + var lastUsedGym by remember { mutableStateOf(null) } - val database = remember { OpenClimbDatabase.getDatabase(context) } + val database = remember { AscentlyDatabase.getDatabase(context) } val repository = remember { ClimbRepository(database, context) } val syncService = remember { SyncService(context, repository) } val viewModel: ClimbViewModel = @@ -115,7 +115,7 @@ fun OpenClimbApp( LaunchedEffect(shortcutAction, activeSession, gyms, lastUsedGym) { if (shortcutAction == AppShortcutManager.ACTION_START_SESSION && gyms.isNotEmpty()) { android.util.Log.d( - "OpenClimbApp", + "AscentlyApp", "Processing shortcut action: activeSession=$activeSession, gyms.size=${gyms.size}, lastUsedGymId=$lastUsedGymId, lastUsedGym=${lastUsedGym?.name}" ) @@ -125,12 +125,12 @@ fun OpenClimbApp( context ) ) { - android.util.Log.d("OpenClimbApp", "Showing notification permission dialog") + android.util.Log.d("AscentlyApp", "Showing notification permission dialog") showNotificationPermissionDialog = true } else { if (gyms.size == 1) { android.util.Log.d( - "OpenClimbApp", + "AscentlyApp", "Starting session with single gym: ${gyms.first().name}" ) viewModel.startSession(context, gyms.first().id) @@ -141,13 +141,13 @@ fun OpenClimbApp( if (targetGym != null) { android.util.Log.d( - "OpenClimbApp", + "AscentlyApp", "Starting session with target gym: ${targetGym.name}" ) viewModel.startSession(context, targetGym.id) } else { android.util.Log.d( - "OpenClimbApp", + "AscentlyApp", "No target gym found, navigating to selection" ) navController.navigate(Screen.AddEditSession()) @@ -156,7 +156,7 @@ fun OpenClimbApp( } } else { android.util.Log.d( - "OpenClimbApp", + "AscentlyApp", "Active session already exists: ${activeSession?.id}" ) } @@ -168,7 +168,7 @@ fun OpenClimbApp( var fabConfig by remember { mutableStateOf(null) } Scaffold( - bottomBar = { OpenClimbBottomNavigation(navController = navController) }, + bottomBar = { AscentlyBottomNavigation(navController = navController) }, floatingActionButton = { fabConfig?.let { config -> FloatingActionButton( @@ -363,7 +363,7 @@ fun OpenClimbApp( } @Composable -fun OpenClimbBottomNavigation(navController: NavHostController) { +fun AscentlyBottomNavigation(navController: NavHostController) { val navBackStackEntry by navController.currentBackStackEntryAsState() val currentRoute = navBackStackEntry?.destination?.route diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/ActiveSessionBanner.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/ActiveSessionBanner.kt similarity index 95% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/ActiveSessionBanner.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/ActiveSessionBanner.kt index 2a3e11e..c54e743 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/ActiveSessionBanner.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/ActiveSessionBanner.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -10,9 +10,9 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.atridad.openclimb.data.model.ClimbSession -import com.atridad.openclimb.data.model.Gym -import com.atridad.openclimb.ui.theme.CustomIcons +import com.atridad.ascently.data.model.ClimbSession +import com.atridad.ascently.data.model.Gym +import com.atridad.ascently.ui.theme.CustomIcons import kotlinx.coroutines.delay import java.time.LocalDateTime import java.time.temporal.ChronoUnit diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/BarChart.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/BarChart.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/BarChart.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/BarChart.kt index cf2f7d2..fdb0d60 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/BarChart.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/BarChart.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Box diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/FullscreenImageViewer.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/FullscreenImageViewer.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/FullscreenImageViewer.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/FullscreenImageViewer.kt index 7be80c5..887d8eb 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/FullscreenImageViewer.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/FullscreenImageViewer.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/ImageDisplay.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/ImageDisplay.kt similarity index 98% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/ImageDisplay.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/ImageDisplay.kt index de190f4..0d983e0 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/ImageDisplay.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/ImageDisplay.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/ImagePicker.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/ImagePicker.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/ImagePicker.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/ImagePicker.kt index 41fdf53..3ff28ef 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/ImagePicker.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/ImagePicker.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import android.Manifest import android.content.pm.PackageManager @@ -25,7 +25,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.core.content.ContextCompat import androidx.core.content.FileProvider -import com.atridad.openclimb.utils.ImageUtils +import com.atridad.ascently.utils.ImageUtils import java.io.File import java.text.SimpleDateFormat import java.util.* diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/LineChart.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/LineChart.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/LineChart.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/LineChart.kt index ac62798..c508b29 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/LineChart.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/LineChart.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Box diff --git a/android/app/src/main/java/com/atridad/ascently/ui/components/NotificationPermissionDialog.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/NotificationPermissionDialog.kt new file mode 100644 index 0000000..5d3f961 --- /dev/null +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/NotificationPermissionDialog.kt @@ -0,0 +1,76 @@ +package com.atridad.ascently.ui.components + +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Notifications +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties + +@Composable +fun NotificationPermissionDialog(onDismiss: () -> Unit, onRequestPermission: () -> Unit) { + Dialog( + onDismissRequest = onDismiss, + properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false) + ) { + Card( + modifier = Modifier.fillMaxWidth().padding(16.dp), + shape = MaterialTheme.shapes.medium + ) { + Column( + modifier = Modifier.padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Icon( + imageVector = Icons.Default.Notifications, + contentDescription = "Notifications", + modifier = Modifier.size(48.dp), + tint = MaterialTheme.colorScheme.primary + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Text( + text = "Enable Notifications", + style = MaterialTheme.typography.headlineSmall, + fontWeight = MaterialTheme.typography.headlineSmall.fontWeight, + textAlign = TextAlign.Center + ) + + Spacer(modifier = Modifier.height(12.dp)) + + Text( + text = + "Ascently needs notification permission to show your active climbing session. This helps you track your progress and ensures the session doesn't get interrupted.", + style = MaterialTheme.typography.bodyMedium, + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + + Spacer(modifier = Modifier.height(24.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + TextButton(onClick = onDismiss, modifier = Modifier.weight(1f)) { + Text("Not Now") + } + + Button( + onClick = { + onRequestPermission() + onDismiss() + }, + modifier = Modifier.weight(1f) + ) { Text("Enable") } + } + } + } + } +} diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/OrientationAwareImage.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/OrientationAwareImage.kt similarity index 98% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/OrientationAwareImage.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/OrientationAwareImage.kt index 3d6f73d..cb0ce38 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/OrientationAwareImage.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/OrientationAwareImage.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import android.graphics.BitmapFactory import android.graphics.Matrix @@ -12,7 +12,7 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.exifinterface.media.ExifInterface -import com.atridad.openclimb.utils.ImageUtils +import com.atridad.ascently.utils.ImageUtils import java.io.File import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/SyncIndicator.kt b/android/app/src/main/java/com/atridad/ascently/ui/components/SyncIndicator.kt similarity index 97% rename from android/app/src/main/java/com/atridad/openclimb/ui/components/SyncIndicator.kt rename to android/app/src/main/java/com/atridad/ascently/ui/components/SyncIndicator.kt index 3403f15..f84bc0e 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/SyncIndicator.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/components/SyncIndicator.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.components +package com.atridad.ascently.ui.components import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/health/HealthConnectCard.kt b/android/app/src/main/java/com/atridad/ascently/ui/health/HealthConnectCard.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/ui/health/HealthConnectCard.kt rename to android/app/src/main/java/com/atridad/ascently/ui/health/HealthConnectCard.kt index 36797a4..086722f 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/health/HealthConnectCard.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/health/HealthConnectCard.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.health +package com.atridad.ascently.ui.health import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.foundation.layout.* @@ -13,7 +13,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.atridad.openclimb.data.health.HealthConnectManager +import com.atridad.ascently.data.health.HealthConnectManager import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/screens/AddEditScreens.kt b/android/app/src/main/java/com/atridad/ascently/ui/screens/AddEditScreens.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/ui/screens/AddEditScreens.kt rename to android/app/src/main/java/com/atridad/ascently/ui/screens/AddEditScreens.kt index 1b785d3..dc21a82 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/screens/AddEditScreens.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/screens/AddEditScreens.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.screens +package com.atridad.ascently.ui.screens import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -17,9 +17,9 @@ import androidx.compose.ui.semantics.Role import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp -import com.atridad.openclimb.data.model.* -import com.atridad.openclimb.ui.components.ImagePicker -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.data.model.* +import com.atridad.ascently.ui.components.ImagePicker +import com.atridad.ascently.ui.viewmodel.ClimbViewModel import java.time.LocalDateTime import kotlinx.coroutines.flow.first diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/screens/AnalyticsScreen.kt b/android/app/src/main/java/com/atridad/ascently/ui/screens/AnalyticsScreen.kt similarity index 95% rename from android/app/src/main/java/com/atridad/openclimb/ui/screens/AnalyticsScreen.kt rename to android/app/src/main/java/com/atridad/ascently/ui/screens/AnalyticsScreen.kt index bd092fa..964f647 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/screens/AnalyticsScreen.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/screens/AnalyticsScreen.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.screens +package com.atridad.ascently.ui.screens import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -9,14 +9,14 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.atridad.openclimb.R -import com.atridad.openclimb.data.model.AttemptResult -import com.atridad.openclimb.data.model.ClimbType -import com.atridad.openclimb.data.model.DifficultySystem -import com.atridad.openclimb.ui.components.BarChart -import com.atridad.openclimb.ui.components.BarChartDataPoint -import com.atridad.openclimb.ui.components.SyncIndicator -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.R +import com.atridad.ascently.data.model.AttemptResult +import com.atridad.ascently.data.model.ClimbType +import com.atridad.ascently.data.model.DifficultySystem +import com.atridad.ascently.ui.components.BarChart +import com.atridad.ascently.ui.components.BarChartDataPoint +import com.atridad.ascently.ui.components.SyncIndicator +import com.atridad.ascently.ui.viewmodel.ClimbViewModel import java.time.LocalDateTime import java.time.format.DateTimeFormatter @@ -39,7 +39,7 @@ fun AnalyticsScreen(viewModel: ClimbViewModel) { ) { Icon( painter = painterResource(id = R.drawable.ic_mountains), - contentDescription = "OpenClimb Logo", + contentDescription = "Ascently Logo", modifier = Modifier.size(32.dp), tint = MaterialTheme.colorScheme.primary ) @@ -200,7 +200,9 @@ fun GradeDistributionChartCard(gradeDistributionData: List, - problems: List, - attempts: List + sessions: List, + problems: List, + attempts: List ): List { if (sessions.isEmpty() || problems.isEmpty() || attempts.isEmpty()) { return emptyList() diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/screens/DetailScreens.kt b/android/app/src/main/java/com/atridad/ascently/ui/screens/DetailScreens.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/ui/screens/DetailScreens.kt rename to android/app/src/main/java/com/atridad/ascently/ui/screens/DetailScreens.kt index 9e32755..8370e7e 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/screens/DetailScreens.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/screens/DetailScreens.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.screens +package com.atridad.ascently.ui.screens import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.clickable @@ -31,11 +31,11 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.lifecycle.viewModelScope -import com.atridad.openclimb.data.model.* -import com.atridad.openclimb.ui.components.FullscreenImageViewer -import com.atridad.openclimb.ui.components.ImageDisplaySection -import com.atridad.openclimb.ui.theme.CustomIcons -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.data.model.* +import com.atridad.ascently.ui.components.FullscreenImageViewer +import com.atridad.ascently.ui.components.ImageDisplaySection +import com.atridad.ascently.ui.theme.CustomIcons +import com.atridad.ascently.ui.viewmodel.ClimbViewModel import java.time.LocalDateTime import java.time.format.DateTimeFormatter import kotlinx.coroutines.flow.first diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/screens/GymsScreen.kt b/android/app/src/main/java/com/atridad/ascently/ui/screens/GymsScreen.kt similarity index 93% rename from android/app/src/main/java/com/atridad/openclimb/ui/screens/GymsScreen.kt rename to android/app/src/main/java/com/atridad/ascently/ui/screens/GymsScreen.kt index 706dc40..c889c62 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/screens/GymsScreen.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/screens/GymsScreen.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.screens +package com.atridad.ascently.ui.screens import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -10,10 +10,10 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.atridad.openclimb.R -import com.atridad.openclimb.data.model.Gym -import com.atridad.openclimb.ui.components.SyncIndicator -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.R +import com.atridad.ascently.data.model.Gym +import com.atridad.ascently.ui.components.SyncIndicator +import com.atridad.ascently.ui.viewmodel.ClimbViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -28,7 +28,7 @@ fun GymsScreen(viewModel: ClimbViewModel, onNavigateToGymDetail: (String) -> Uni ) { Icon( painter = painterResource(id = R.drawable.ic_mountains), - contentDescription = "OpenClimb Logo", + contentDescription = "Ascently Logo", modifier = Modifier.size(32.dp), tint = MaterialTheme.colorScheme.primary ) diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/screens/ProblemsScreen.kt b/android/app/src/main/java/com/atridad/ascently/ui/screens/ProblemsScreen.kt similarity index 96% rename from android/app/src/main/java/com/atridad/openclimb/ui/screens/ProblemsScreen.kt rename to android/app/src/main/java/com/atridad/ascently/ui/screens/ProblemsScreen.kt index 90d20b0..e97033c 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/screens/ProblemsScreen.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/screens/ProblemsScreen.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.screens +package com.atridad.ascently.ui.screens import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -15,14 +15,14 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.atridad.openclimb.R -import com.atridad.openclimb.data.model.Attempt -import com.atridad.openclimb.data.model.AttemptResult -import com.atridad.openclimb.data.model.ClimbType -import com.atridad.openclimb.data.model.Gym -import com.atridad.openclimb.data.model.Problem -import com.atridad.openclimb.ui.components.SyncIndicator -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.R +import com.atridad.ascently.data.model.Attempt +import com.atridad.ascently.data.model.AttemptResult +import com.atridad.ascently.data.model.ClimbType +import com.atridad.ascently.data.model.Gym +import com.atridad.ascently.data.model.Problem +import com.atridad.ascently.ui.components.SyncIndicator +import com.atridad.ascently.ui.viewmodel.ClimbViewModel @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -57,7 +57,7 @@ fun ProblemsScreen(viewModel: ClimbViewModel, onNavigateToProblemDetail: (String ) { Icon( painter = painterResource(id = R.drawable.ic_mountains), - contentDescription = "OpenClimb Logo", + contentDescription = "Ascently Logo", modifier = Modifier.size(32.dp), tint = MaterialTheme.colorScheme.primary ) diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/screens/SessionsScreen.kt b/android/app/src/main/java/com/atridad/ascently/ui/screens/SessionsScreen.kt similarity index 95% rename from android/app/src/main/java/com/atridad/openclimb/ui/screens/SessionsScreen.kt rename to android/app/src/main/java/com/atridad/ascently/ui/screens/SessionsScreen.kt index 4248b27..f250ee5 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/screens/SessionsScreen.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/screens/SessionsScreen.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.screens +package com.atridad.ascently.ui.screens import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn @@ -16,12 +16,12 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import com.atridad.openclimb.R -import com.atridad.openclimb.data.model.ClimbSession -import com.atridad.openclimb.data.model.SessionStatus -import com.atridad.openclimb.ui.components.ActiveSessionBanner -import com.atridad.openclimb.ui.components.SyncIndicator -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.R +import com.atridad.ascently.data.model.ClimbSession +import com.atridad.ascently.data.model.SessionStatus +import com.atridad.ascently.ui.components.ActiveSessionBanner +import com.atridad.ascently.ui.components.SyncIndicator +import com.atridad.ascently.ui.viewmodel.ClimbViewModel import java.time.LocalDateTime import java.time.format.DateTimeFormatter @@ -46,7 +46,7 @@ fun SessionsScreen(viewModel: ClimbViewModel, onNavigateToSessionDetail: (String ) { Icon( painter = painterResource(id = R.drawable.ic_mountains), - contentDescription = "OpenClimb Logo", + contentDescription = "Ascently Logo", modifier = Modifier.size(32.dp), tint = MaterialTheme.colorScheme.primary ) diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/screens/SettingsScreen.kt b/android/app/src/main/java/com/atridad/ascently/ui/screens/SettingsScreen.kt similarity index 98% rename from android/app/src/main/java/com/atridad/openclimb/ui/screens/SettingsScreen.kt rename to android/app/src/main/java/com/atridad/ascently/ui/screens/SettingsScreen.kt index 8d9e0ea..05420fc 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/screens/SettingsScreen.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/screens/SettingsScreen.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.screens +package com.atridad.ascently.ui.screens import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -15,10 +15,10 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.atridad.openclimb.R -import com.atridad.openclimb.ui.components.SyncIndicator -import com.atridad.openclimb.ui.health.HealthConnectCard -import com.atridad.openclimb.ui.viewmodel.ClimbViewModel +import com.atridad.ascently.R +import com.atridad.ascently.ui.components.SyncIndicator +import com.atridad.ascently.ui.health.HealthConnectCard +import com.atridad.ascently.ui.viewmodel.ClimbViewModel import java.io.File import java.time.Instant import kotlinx.coroutines.launch @@ -86,7 +86,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) { // Only allow ZIP files if (!fileName.lowercase().endsWith(".zip")) { viewModel.setError( - "Only ZIP files are supported for import. Please use a ZIP file exported from OpenClimb." + "Only ZIP files are supported for import. Please use a ZIP file exported from Ascently." ) return@let } @@ -129,7 +129,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) { ) { Icon( painter = painterResource(id = R.drawable.ic_mountains), - contentDescription = "OpenClimb Logo", + contentDescription = "Ascently Logo", modifier = Modifier.size(32.dp), tint = MaterialTheme.colorScheme.primary ) @@ -336,7 +336,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) { ListItem( headlineContent = { Text("Setup Sync") }, supportingContent = { - Text("Connect to your OpenClimb sync server") + Text("Connect to your Ascently sync server") }, leadingContent = { Icon(Icons.Default.CloudSync, contentDescription = null) @@ -421,7 +421,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) { TextButton( onClick = { val defaultFileName = - "openclimb_export_${ + "ascently_export_${ java.time.LocalDateTime.now() .toString() .replace(":", "-") @@ -604,11 +604,11 @@ fun SettingsScreen(viewModel: ClimbViewModel) { painterResource( id = R.drawable.ic_mountains ), - contentDescription = "OpenClimb Logo", + contentDescription = "Ascently Logo", modifier = Modifier.size(24.dp), tint = MaterialTheme.colorScheme.primary ) - Text("OpenClimb") + Text("Ascently") } }, supportingContent = { Text("Track your climbing progress") }, diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/theme/Color.kt b/android/app/src/main/java/com/atridad/ascently/ui/theme/Color.kt similarity index 98% rename from android/app/src/main/java/com/atridad/openclimb/ui/theme/Color.kt rename to android/app/src/main/java/com/atridad/ascently/ui/theme/Color.kt index 989ace4..06a7993 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/theme/Color.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/theme/Color.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.theme +package com.atridad.ascently.ui.theme import androidx.compose.ui.graphics.Color diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/theme/CustomIcons.kt b/android/app/src/main/java/com/atridad/ascently/ui/theme/CustomIcons.kt similarity index 94% rename from android/app/src/main/java/com/atridad/openclimb/ui/theme/CustomIcons.kt rename to android/app/src/main/java/com/atridad/ascently/ui/theme/CustomIcons.kt index 73936f7..ba536ef 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/theme/CustomIcons.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/theme/CustomIcons.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.theme +package com.atridad.ascently.ui.theme import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/theme/Theme.kt b/android/app/src/main/java/com/atridad/ascently/ui/theme/Theme.kt similarity index 98% rename from android/app/src/main/java/com/atridad/openclimb/ui/theme/Theme.kt rename to android/app/src/main/java/com/atridad/ascently/ui/theme/Theme.kt index 1a8ecf8..2c137da 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/theme/Theme.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/theme/Theme.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.theme +package com.atridad.ascently.ui.theme import android.app.Activity import androidx.compose.foundation.isSystemInDarkTheme @@ -88,7 +88,7 @@ private val LightColorScheme = lightColorScheme( ) @Composable -fun OpenClimbTheme( +fun AscentlyTheme( darkTheme: Boolean = isSystemInDarkTheme(), // Dynamic color is available on Android 12+ and provides full Material You theming // When enabled, it adapts to the user's system wallpaper colors diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/theme/Type.kt b/android/app/src/main/java/com/atridad/ascently/ui/theme/Type.kt similarity index 92% rename from android/app/src/main/java/com/atridad/openclimb/ui/theme/Type.kt rename to android/app/src/main/java/com/atridad/ascently/ui/theme/Type.kt index 38ce75a..faa4bbb 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/theme/Type.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/theme/Type.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.ui.theme +package com.atridad.ascently.ui.theme import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/viewmodel/ClimbViewModel.kt b/android/app/src/main/java/com/atridad/ascently/ui/viewmodel/ClimbViewModel.kt similarity index 96% rename from android/app/src/main/java/com/atridad/openclimb/ui/viewmodel/ClimbViewModel.kt rename to android/app/src/main/java/com/atridad/ascently/ui/viewmodel/ClimbViewModel.kt index cc24c84..361801c 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/viewmodel/ClimbViewModel.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/viewmodel/ClimbViewModel.kt @@ -1,17 +1,17 @@ -package com.atridad.openclimb.ui.viewmodel +package com.atridad.ascently.ui.viewmodel import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.atridad.openclimb.data.health.HealthConnectManager -import com.atridad.openclimb.data.model.* -import com.atridad.openclimb.data.repository.ClimbRepository -import com.atridad.openclimb.data.sync.SyncService -import com.atridad.openclimb.service.SessionTrackingService -import com.atridad.openclimb.utils.ImageNamingUtils -import com.atridad.openclimb.utils.ImageUtils -import com.atridad.openclimb.utils.SessionShareUtils -import com.atridad.openclimb.widget.ClimbStatsWidgetProvider +import com.atridad.ascently.data.health.HealthConnectManager +import com.atridad.ascently.data.model.* +import com.atridad.ascently.data.repository.ClimbRepository +import com.atridad.ascently.data.sync.SyncService +import com.atridad.ascently.service.SessionTrackingService +import com.atridad.ascently.utils.ImageNamingUtils +import com.atridad.ascently.utils.ImageUtils +import com.atridad.ascently.utils.SessionShareUtils +import com.atridad.ascently.widget.ClimbStatsWidgetProvider import java.io.File import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.* @@ -260,7 +260,7 @@ class ClimbViewModel( viewModelScope.launch { android.util.Log.d("ClimbViewModel", "startSession called with gymId: $gymId") - if (!com.atridad.openclimb.utils.NotificationPermissionUtils + if (!com.atridad.ascently.utils.NotificationPermissionUtils .isNotificationPermissionGranted(context) ) { android.util.Log.d("ClimbViewModel", "Notification permission not granted") @@ -305,7 +305,7 @@ class ClimbViewModel( fun endSession(context: Context, sessionId: String) { viewModelScope.launch { - if (!com.atridad.openclimb.utils.NotificationPermissionUtils + if (!com.atridad.ascently.utils.NotificationPermissionUtils .isNotificationPermissionGranted(context) ) { _uiState.value = @@ -416,7 +416,7 @@ class ClimbViewModel( if (!file.name.lowercase().endsWith(".zip")) { throw Exception( - "Only ZIP files are supported for import. Please use a ZIP file exported from OpenClimb." + "Only ZIP files are supported for import. Please use a ZIP file exported from Ascently." ) } diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/viewmodel/ClimbViewModelFactory.kt b/android/app/src/main/java/com/atridad/ascently/ui/viewmodel/ClimbViewModelFactory.kt similarity index 80% rename from android/app/src/main/java/com/atridad/openclimb/ui/viewmodel/ClimbViewModelFactory.kt rename to android/app/src/main/java/com/atridad/ascently/ui/viewmodel/ClimbViewModelFactory.kt index 5a96ecf..237048f 100644 --- a/android/app/src/main/java/com/atridad/openclimb/ui/viewmodel/ClimbViewModelFactory.kt +++ b/android/app/src/main/java/com/atridad/ascently/ui/viewmodel/ClimbViewModelFactory.kt @@ -1,10 +1,10 @@ -package com.atridad.openclimb.ui.viewmodel +package com.atridad.ascently.ui.viewmodel import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.atridad.openclimb.data.repository.ClimbRepository -import com.atridad.openclimb.data.sync.SyncService +import com.atridad.ascently.data.repository.ClimbRepository +import com.atridad.ascently.data.sync.SyncService class ClimbViewModelFactory( private val repository: ClimbRepository, diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/DateFormatUtils.kt b/android/app/src/main/java/com/atridad/ascently/utils/DateFormatUtils.kt similarity index 97% rename from android/app/src/main/java/com/atridad/openclimb/utils/DateFormatUtils.kt rename to android/app/src/main/java/com/atridad/ascently/utils/DateFormatUtils.kt index 17058fe..2c32fca 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/DateFormatUtils.kt +++ b/android/app/src/main/java/com/atridad/ascently/utils/DateFormatUtils.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.utils +package com.atridad.ascently.utils import java.time.Instant import java.time.ZoneOffset diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/ImageNamingUtils.kt b/android/app/src/main/java/com/atridad/ascently/utils/ImageNamingUtils.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/utils/ImageNamingUtils.kt rename to android/app/src/main/java/com/atridad/ascently/utils/ImageNamingUtils.kt index 5aabe5b..dfdf41f 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/ImageNamingUtils.kt +++ b/android/app/src/main/java/com/atridad/ascently/utils/ImageNamingUtils.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.utils +package com.atridad.ascently.utils import java.security.MessageDigest import java.util.* diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/ImageUtils.kt b/android/app/src/main/java/com/atridad/ascently/utils/ImageUtils.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/utils/ImageUtils.kt rename to android/app/src/main/java/com/atridad/ascently/utils/ImageUtils.kt index 9a8ae77..2a2d74f 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/ImageUtils.kt +++ b/android/app/src/main/java/com/atridad/ascently/utils/ImageUtils.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.utils +package com.atridad.ascently.utils import android.annotation.SuppressLint import android.content.Context diff --git a/android/app/src/main/java/com/atridad/ascently/utils/MigrationManager.kt b/android/app/src/main/java/com/atridad/ascently/utils/MigrationManager.kt new file mode 100644 index 0000000..7a30c0a --- /dev/null +++ b/android/app/src/main/java/com/atridad/ascently/utils/MigrationManager.kt @@ -0,0 +1,175 @@ +package com.atridad.ascently.utils + +import android.content.Context +import android.content.SharedPreferences +import android.util.Log +import androidx.core.content.edit + +/** + * Handles migration of data from OpenClimb to Ascently This includes SharedPreferences, database + * names, and other local storage + */ +class MigrationManager(private val context: Context) { + + companion object { + private const val TAG = "MigrationManager" + private const val MIGRATION_PREFS = "ascently_migration_state" + private const val MIGRATION_COMPLETED_KEY = "openclimb_to_ascently_completed" + } + + private val migrationPrefs: SharedPreferences = + context.getSharedPreferences(MIGRATION_PREFS, Context.MODE_PRIVATE) + + /** + * Perform migration from OpenClimb to Ascently if needed This should be called early in app + * startup + */ + fun migrateIfNeeded() { + if (migrationPrefs.getBoolean(MIGRATION_COMPLETED_KEY, false)) { + Log.d(TAG, "Migration already completed, skipping") + return + } + + Log.i(TAG, "🔄 Starting migration from OpenClimb to Ascently...") + var migrationCount = 0 + + // Migrate SharedPreferences + migrationCount += migrateSharedPreferences() + + // Mark migration as completed + migrationPrefs.edit { putBoolean(MIGRATION_COMPLETED_KEY, true) } + + if (migrationCount > 0) { + Log.i( + TAG, + "🎉 Migration completed! Migrated $migrationCount items from OpenClimb to Ascently" + ) + } else { + Log.i(TAG, "ℹ️ No OpenClimb data found to migrate") + } + } + + /** Migrate SharedPreferences from OpenClimb naming to Ascently naming */ + private fun migrateSharedPreferences(): Int { + var count = 0 + + // Define preference file migrations + val preferenceFileMigrations = + listOf( + "openclimb_data_state" to "ascently_data_state", + "health_connect_prefs" to "health_connect_prefs", // Keep same name + "deleted_items" to "deleted_items", // Keep same name + "sync_preferences" to "sync_preferences" // Keep same name + ) + + for ((oldFileName, newFileName) in preferenceFileMigrations) { + if (oldFileName != newFileName) { + count += migratePreferenceFile(oldFileName, newFileName) + } + } + + // Migrate specific keys within preference files + count += migratePreferenceKeys() + + return count + } + + /** Migrate an entire SharedPreferences file */ + private fun migratePreferenceFile(oldFileName: String, newFileName: String): Int { + val oldPrefs = context.getSharedPreferences(oldFileName, Context.MODE_PRIVATE) + val newPrefs = context.getSharedPreferences(newFileName, Context.MODE_PRIVATE) + + // If old prefs exist and new prefs are empty, migrate + if (oldPrefs.all.isNotEmpty() && newPrefs.all.isEmpty()) { + newPrefs.edit { + oldPrefs.all.forEach { (key, value) -> + when (value) { + is String -> putString(key, value) + is Int -> putInt(key, value) + is Long -> putLong(key, value) + is Float -> putFloat(key, value) + is Boolean -> putBoolean(key, value) + is Set<*> -> { + @Suppress("UNCHECKED_CAST") putStringSet(key, value as Set) + } + } + } + } + + // Clear old preferences + oldPrefs.edit { clear() } + + Log.d( + TAG, + "✅ Migrated preference file: $oldFileName → $newFileName (${oldPrefs.all.size} keys)" + ) + return oldPrefs.all.size + } + + return 0 + } + + /** Migrate specific keys within preference files that might contain openclimb references */ + private fun migratePreferenceKeys(): Int { + var count = 0 + + // Check for any openclimb-prefixed keys across all preference files + val preferencesToCheck = + listOf( + "ascently_data_state", + "health_connect_prefs", + "deleted_items", + "sync_preferences" + ) + + for (prefFileName in preferencesToCheck) { + val prefs = context.getSharedPreferences(prefFileName, Context.MODE_PRIVATE) + val keysToMigrate = mutableListOf>() + + // Find keys that start with openclimb_ and should be ascently_ + prefs.all.keys.forEach { key -> + if (key.startsWith("openclimb_")) { + val newKey = key.replace("openclimb_", "ascently_") + keysToMigrate.add(key to newKey) + } + } + + // Perform the key migrations + if (keysToMigrate.isNotEmpty()) { + prefs.edit { + keysToMigrate.forEach { (oldKey, newKey) -> + val value = prefs.all[oldKey] + when (value) { + is String -> putString(newKey, value) + is Int -> putInt(newKey, value) + is Long -> putLong(newKey, value) + is Float -> putFloat(newKey, value) + is Boolean -> putBoolean(newKey, value) + is Set<*> -> { + @Suppress("UNCHECKED_CAST") + putStringSet(newKey, value as Set) + } + } + remove(oldKey) + } + } + + Log.d(TAG, "✅ Migrated ${keysToMigrate.size} keys in $prefFileName") + count += keysToMigrate.size + } + } + + return count + } + + /** Check if migration has been completed */ + fun isMigrationCompleted(): Boolean { + return migrationPrefs.getBoolean(MIGRATION_COMPLETED_KEY, false) + } + + /** Reset migration state (for testing purposes) */ + fun resetMigrationState() { + migrationPrefs.edit { putBoolean(MIGRATION_COMPLETED_KEY, false) } + Log.d(TAG, "Migration state reset") + } +} diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/NotificationPermissionUtils.kt b/android/app/src/main/java/com/atridad/ascently/utils/NotificationPermissionUtils.kt similarity index 95% rename from android/app/src/main/java/com/atridad/openclimb/utils/NotificationPermissionUtils.kt rename to android/app/src/main/java/com/atridad/ascently/utils/NotificationPermissionUtils.kt index 318dec5..50b4c7f 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/NotificationPermissionUtils.kt +++ b/android/app/src/main/java/com/atridad/ascently/utils/NotificationPermissionUtils.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.utils +package com.atridad.ascently.utils import android.Manifest import android.content.Context diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/SessionShareUtils.kt b/android/app/src/main/java/com/atridad/ascently/utils/SessionShareUtils.kt similarity index 99% rename from android/app/src/main/java/com/atridad/openclimb/utils/SessionShareUtils.kt rename to android/app/src/main/java/com/atridad/ascently/utils/SessionShareUtils.kt index 711da13..789a312 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/SessionShareUtils.kt +++ b/android/app/src/main/java/com/atridad/ascently/utils/SessionShareUtils.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.utils +package com.atridad.ascently.utils import android.content.Context import android.content.Intent @@ -7,7 +7,7 @@ import android.graphics.drawable.GradientDrawable import androidx.core.content.FileProvider import androidx.core.graphics.createBitmap import androidx.core.graphics.toColorInt -import com.atridad.openclimb.data.model.* +import com.atridad.ascently.data.model.* import java.io.File import java.io.FileOutputStream import java.time.LocalDateTime @@ -382,7 +382,7 @@ object SessionShareUtils { isAntiAlias = true textAlign = Paint.Align.CENTER } - canvas.drawText("OpenClimb", width / 2f, height - 40f, brandingPaint) + canvas.drawText("Ascently", width / 2f, height - 40f, brandingPaint) // Save to file val shareDir = File(context.cacheDir, "shares") @@ -481,7 +481,7 @@ object SessionShareUtils { action = Intent.ACTION_SEND type = "image/png" putExtra(Intent.EXTRA_STREAM, uri) - putExtra(Intent.EXTRA_TEXT, "Check out my climbing session! #OpenClimb") + putExtra(Intent.EXTRA_TEXT, "Check out my climbing session! #Ascently") addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/ShortcutManager.kt b/android/app/src/main/java/com/atridad/ascently/utils/ShortcutManager.kt similarity index 90% rename from android/app/src/main/java/com/atridad/openclimb/utils/ShortcutManager.kt rename to android/app/src/main/java/com/atridad/ascently/utils/ShortcutManager.kt index 02052ac..94b64de 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/ShortcutManager.kt +++ b/android/app/src/main/java/com/atridad/ascently/utils/ShortcutManager.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.utils +package com.atridad.ascently.utils import android.content.Context import android.content.Intent @@ -7,23 +7,23 @@ import android.content.pm.ShortcutManager import android.graphics.drawable.Icon import android.os.Build import androidx.annotation.RequiresApi -import com.atridad.openclimb.MainActivity -import com.atridad.openclimb.R +import com.atridad.ascently.MainActivity +import com.atridad.ascently.R object AppShortcutManager { const val SHORTCUT_START_SESSION = "start_session" const val SHORTCUT_END_SESSION = "end_session" - const val ACTION_START_SESSION = "com.atridad.openclimb.action.START_SESSION" - const val ACTION_END_SESSION = "com.atridad.openclimb.action.END_SESSION" + const val ACTION_START_SESSION = "com.atridad.ascently.action.START_SESSION" + const val ACTION_END_SESSION = "com.atridad.ascently.action.END_SESSION" /** Updates the app shortcuts based on current session state */ fun updateShortcuts( context: Context, hasActiveSession: Boolean, hasGyms: Boolean, - lastUsedGym: com.atridad.openclimb.data.model.Gym? = null + lastUsedGym: com.atridad.ascently.data.model.Gym? = null ) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { val shortcutManager = context.getSystemService(ShortcutManager::class.java) @@ -45,7 +45,7 @@ object AppShortcutManager { @RequiresApi(Build.VERSION_CODES.N_MR1) private fun createStartSessionShortcut( context: Context, - lastUsedGym: com.atridad.openclimb.data.model.Gym? = null + lastUsedGym: com.atridad.ascently.data.model.Gym? = null ): ShortcutInfo { val startIntent = Intent(context, MainActivity::class.java).apply { diff --git a/android/app/src/main/java/com/atridad/openclimb/utils/ZipExportImportUtils.kt b/android/app/src/main/java/com/atridad/ascently/utils/ZipExportImportUtils.kt similarity index 97% rename from android/app/src/main/java/com/atridad/openclimb/utils/ZipExportImportUtils.kt rename to android/app/src/main/java/com/atridad/ascently/utils/ZipExportImportUtils.kt index 6456606..9db6c8b 100644 --- a/android/app/src/main/java/com/atridad/openclimb/utils/ZipExportImportUtils.kt +++ b/android/app/src/main/java/com/atridad/ascently/utils/ZipExportImportUtils.kt @@ -1,8 +1,8 @@ -package com.atridad.openclimb.utils +package com.atridad.ascently.utils import android.content.Context -import com.atridad.openclimb.data.format.BackupProblem -import com.atridad.openclimb.data.format.ClimbDataBackup +import com.atridad.ascently.data.format.BackupProblem +import com.atridad.ascently.data.format.ClimbDataBackup import java.io.File import java.io.FileInputStream import java.io.FileOutputStream @@ -33,14 +33,14 @@ object ZipExportImportUtils { context.getExternalFilesDir( android.os.Environment.DIRECTORY_DOCUMENTS ), - "OpenClimb" + "Ascently" ) if (!exportDir.exists()) { exportDir.mkdirs() } val timestamp = LocalDateTime.now().toString().replace(":", "-").replace(".", "-") - val zipFile = File(exportDir, "openclimb_export_$timestamp.zip") + val zipFile = File(exportDir, "ascently_export_$timestamp.zip") try { ZipOutputStream(FileOutputStream(zipFile)).use { zipOut -> @@ -182,8 +182,8 @@ object ZipExportImportUtils { referencedImagePaths: Set ): String { return buildString { - appendLine("OpenClimb Export Metadata") - appendLine("=======================") + appendLine("Ascently Export Metadata") + appendLine("========================") appendLine("Export Date: ${exportData.exportedAt}") appendLine("Version: ${exportData.version}") appendLine("Gyms: ${exportData.gyms.size}") diff --git a/android/app/src/main/java/com/atridad/openclimb/widget/ClimbStatsWidgetProvider.kt b/android/app/src/main/java/com/atridad/ascently/widget/ClimbStatsWidgetProvider.kt similarity index 94% rename from android/app/src/main/java/com/atridad/openclimb/widget/ClimbStatsWidgetProvider.kt rename to android/app/src/main/java/com/atridad/ascently/widget/ClimbStatsWidgetProvider.kt index beee244..52e27d0 100644 --- a/android/app/src/main/java/com/atridad/openclimb/widget/ClimbStatsWidgetProvider.kt +++ b/android/app/src/main/java/com/atridad/ascently/widget/ClimbStatsWidgetProvider.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb.widget +package com.atridad.ascently.widget import android.app.PendingIntent import android.appwidget.AppWidgetManager @@ -7,10 +7,10 @@ import android.content.ComponentName import android.content.Context import android.content.Intent import android.widget.RemoteViews -import com.atridad.openclimb.MainActivity -import com.atridad.openclimb.R -import com.atridad.openclimb.data.database.OpenClimbDatabase -import com.atridad.openclimb.data.repository.ClimbRepository +import com.atridad.ascently.MainActivity +import com.atridad.ascently.R +import com.atridad.ascently.data.database.AscentlyDatabase +import com.atridad.ascently.data.repository.ClimbRepository import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -45,7 +45,7 @@ class ClimbStatsWidgetProvider : AppWidgetProvider() { ) { coroutineScope.launch { try { - val database = OpenClimbDatabase.getDatabase(context) + val database = AscentlyDatabase.getDatabase(context) val repository = ClimbRepository(database, context) // Fetch stats data @@ -65,10 +65,10 @@ class ClimbStatsWidgetProvider : AppWidgetProvider() { attempts.any { attempt -> attempt.problemId == problem.id && (attempt.result == - com.atridad.openclimb.data.model + com.atridad.ascently.data.model .AttemptResult.SUCCESS || attempt.result == - com.atridad.openclimb.data.model + com.atridad.ascently.data.model .AttemptResult.FLASH) } } diff --git a/android/app/src/main/java/com/atridad/openclimb/ui/components/NotificationPermissionDialog.kt b/android/app/src/main/java/com/atridad/openclimb/ui/components/NotificationPermissionDialog.kt deleted file mode 100644 index 9b463ea..0000000 --- a/android/app/src/main/java/com/atridad/openclimb/ui/components/NotificationPermissionDialog.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.atridad.openclimb.ui.components - -import androidx.compose.foundation.layout.* -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Notifications -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties - -@Composable -fun NotificationPermissionDialog( - onDismiss: () -> Unit, - onRequestPermission: () -> Unit -) { - Dialog( - onDismissRequest = onDismiss, - properties = DialogProperties( - dismissOnBackPress = false, - dismissOnClickOutside = false - ) - ) { - Card( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - shape = MaterialTheme.shapes.medium - ) { - Column( - modifier = Modifier.padding(24.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Icon( - imageVector = Icons.Default.Notifications, - contentDescription = "Notifications", - modifier = Modifier.size(48.dp), - tint = MaterialTheme.colorScheme.primary - ) - - Spacer(modifier = Modifier.height(16.dp)) - - Text( - text = "Enable Notifications", - style = MaterialTheme.typography.headlineSmall, - fontWeight = MaterialTheme.typography.headlineSmall.fontWeight, - textAlign = TextAlign.Center - ) - - Spacer(modifier = Modifier.height(12.dp)) - - Text( - text = "OpenClimb needs notification permission to show your active climbing session. This helps you track your progress and ensures the session doesn't get interrupted.", - style = MaterialTheme.typography.bodyMedium, - textAlign = TextAlign.Center, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - - Spacer(modifier = Modifier.height(24.dp)) - - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - TextButton( - onClick = onDismiss, - modifier = Modifier.weight(1f) - ) { - Text("Not Now") - } - - Button( - onClick = { - onRequestPermission() - onDismiss() - }, - modifier = Modifier.weight(1f) - ) { - Text("Enable") - } - } - } - } - } -} diff --git a/android/app/src/main/res/layout/widget_climb_stats.xml b/android/app/src/main/res/layout/widget_climb_stats.xml index b8ba2cf..c36d38d 100644 --- a/android/app/src/main/res/layout/widget_climb_stats.xml +++ b/android/app/src/main/res/layout/widget_climb_stats.xml @@ -26,7 +26,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:text="OpenClimb" + android:text="Ascently" android:textSize="16sp" android:textStyle="bold" android:textColor="@color/widget_text_primary" /> diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index b600281..8434f4c 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - OpenClimb + Ascently Tracks active climbing sessions and displays session information in the notification area diff --git a/android/app/src/main/res/values/themes.xml b/android/app/src/main/res/values/themes.xml index c8ca7f1..39e68ea 100644 --- a/android/app/src/main/res/values/themes.xml +++ b/android/app/src/main/res/values/themes.xml @@ -1,10 +1,10 @@ - - \ No newline at end of file + diff --git a/android/app/src/test/java/com/atridad/openclimb/BusinessLogicTests.kt b/android/app/src/test/java/com/atridad/openclimb/BusinessLogicTests.kt index 7c2352d..120438e 100644 --- a/android/app/src/test/java/com/atridad/openclimb/BusinessLogicTests.kt +++ b/android/app/src/test/java/com/atridad/openclimb/BusinessLogicTests.kt @@ -1,7 +1,7 @@ -package com.atridad.openclimb +package com.atridad.ascently -import com.atridad.openclimb.data.format.* -import com.atridad.openclimb.data.model.* +import com.atridad.ascently.data.format.* +import com.atridad.ascently.data.model.* import java.time.LocalDateTime import java.time.format.DateTimeFormatter import org.junit.Assert.* diff --git a/android/app/src/test/java/com/atridad/openclimb/DataModelTests.kt b/android/app/src/test/java/com/atridad/openclimb/DataModelTests.kt index 5c4b528..0fcda04 100644 --- a/android/app/src/test/java/com/atridad/openclimb/DataModelTests.kt +++ b/android/app/src/test/java/com/atridad/openclimb/DataModelTests.kt @@ -1,7 +1,7 @@ -package com.atridad.openclimb +package com.atridad.ascently -import com.atridad.openclimb.data.format.* -import com.atridad.openclimb.data.model.* +import com.atridad.ascently.data.format.* +import com.atridad.ascently.data.model.* import java.time.Instant import java.time.format.DateTimeFormatter import org.junit.Assert.* diff --git a/android/app/src/test/java/com/atridad/openclimb/SyncMergeLogicTest.kt b/android/app/src/test/java/com/atridad/openclimb/SyncMergeLogicTest.kt index e73c549..f80fd7a 100644 --- a/android/app/src/test/java/com/atridad/openclimb/SyncMergeLogicTest.kt +++ b/android/app/src/test/java/com/atridad/openclimb/SyncMergeLogicTest.kt @@ -1,7 +1,7 @@ -package com.atridad.openclimb +package com.atridad.ascently -import com.atridad.openclimb.data.format.* -import com.atridad.openclimb.data.model.* +import com.atridad.ascently.data.format.* +import com.atridad.ascently.data.model.* import org.junit.Assert.* import org.junit.Test diff --git a/android/app/src/test/java/com/atridad/openclimb/UtilityTests.kt b/android/app/src/test/java/com/atridad/openclimb/UtilityTests.kt index 58cc1f4..5f9395c 100644 --- a/android/app/src/test/java/com/atridad/openclimb/UtilityTests.kt +++ b/android/app/src/test/java/com/atridad/openclimb/UtilityTests.kt @@ -1,4 +1,4 @@ -package com.atridad.openclimb +package com.atridad.ascently import java.time.LocalDateTime import java.time.format.DateTimeFormatter diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 8d5dd2f..a0441d2 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -11,6 +11,7 @@ pluginManagement { gradlePluginPortal() } } + dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { @@ -20,5 +21,6 @@ dependencyResolutionManagement { } } -rootProject.name = "OpenClimb" +rootProject.name = "Ascently" + include(":app") diff --git a/ios/OpenClimb.xcodeproj/LiveActivityManager.swift b/ios/Ascently.xcodeproj/LiveActivityManager.swift similarity index 100% rename from ios/OpenClimb.xcodeproj/LiveActivityManager.swift rename to ios/Ascently.xcodeproj/LiveActivityManager.swift diff --git a/ios/OpenClimb.xcodeproj/project.pbxproj b/ios/Ascently.xcodeproj/project.pbxproj similarity index 87% rename from ios/OpenClimb.xcodeproj/project.pbxproj rename to ios/Ascently.xcodeproj/project.pbxproj index c9c880d..0f0651d 100644 --- a/ios/OpenClimb.xcodeproj/project.pbxproj +++ b/ios/Ascently.xcodeproj/project.pbxproj @@ -20,7 +20,7 @@ containerPortal = D24C19602E75002A0045894C /* Project object */; proxyType = 1; remoteGlobalIDString = D24C19672E75002A0045894C; - remoteInfo = OpenClimb; + remoteInfo = Ascently; }; D2FE949E2E78FEE1008CDB25 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -46,9 +46,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - D24C19682E75002A0045894C /* OpenClimb.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OpenClimb.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D24C19682E75002A0045894C /* Ascently.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Ascently.app; sourceTree = BUILT_PRODUCTS_DIR; }; D268B79E2E83894A003AA641 /* SessionStatusLiveExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionStatusLiveExtension.entitlements; sourceTree = ""; }; - D2F32FAD2E90B26500B1BC56 /* OpenClimbTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenClimbTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + D2F32FAD2E90B26500B1BC56 /* AscentlyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AscentlyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D2FE94802E78E958008CDB25 /* ActivityKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ActivityKit.framework; path = System/Library/Frameworks/ActivityKit.framework; sourceTree = SDKROOT; }; D2FE948B2E78FEE0008CDB25 /* SessionStatusLiveExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionStatusLiveExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; D2FE948C2E78FEE0008CDB25 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; @@ -56,12 +56,12 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - D28C3C8B2E75111D00F7AEE9 /* Exceptions for "OpenClimb" folder in "OpenClimb" target */ = { + D28C3C8B2E75111D00F7AEE9 /* Exceptions for "Ascently" folder in "Ascently" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( Info.plist, ); - target = D24C19672E75002A0045894C /* OpenClimb */; + target = D24C19672E75002A0045894C /* Ascently */; }; D2FE94A42E78FEE1008CDB25 /* Exceptions for "SessionStatusLive" folder in "SessionStatusLiveExtension" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; @@ -73,17 +73,17 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ - D24C196A2E75002A0045894C /* OpenClimb */ = { + D24C196A2E75002A0045894C /* Ascently */ = { isa = PBXFileSystemSynchronizedRootGroup; exceptions = ( - D28C3C8B2E75111D00F7AEE9 /* Exceptions for "OpenClimb" folder in "OpenClimb" target */, + D28C3C8B2E75111D00F7AEE9 /* Exceptions for "Ascently" folder in "Ascently" target */, ); - path = OpenClimb; + path = Ascently; sourceTree = ""; }; - D2F32FAE2E90B26500B1BC56 /* OpenClimbTests */ = { + D2F32FAE2E90B26500B1BC56 /* AscentlyTests */ = { isa = PBXFileSystemSynchronizedRootGroup; - path = OpenClimbTests; + path = AscentlyTests; sourceTree = ""; }; D2FE94902E78FEE0008CDB25 /* SessionStatusLive */ = { @@ -129,9 +129,9 @@ isa = PBXGroup; children = ( D268B79E2E83894A003AA641 /* SessionStatusLiveExtension.entitlements */, - D24C196A2E75002A0045894C /* OpenClimb */, + D24C196A2E75002A0045894C /* Ascently */, D2FE94902E78FEE0008CDB25 /* SessionStatusLive */, - D2F32FAE2E90B26500B1BC56 /* OpenClimbTests */, + D2F32FAE2E90B26500B1BC56 /* AscentlyTests */, D2FE947F2E78E958008CDB25 /* Frameworks */, D24C19692E75002A0045894C /* Products */, ); @@ -140,9 +140,9 @@ D24C19692E75002A0045894C /* Products */ = { isa = PBXGroup; children = ( - D24C19682E75002A0045894C /* OpenClimb.app */, + D24C19682E75002A0045894C /* Ascently.app */, D2FE948B2E78FEE0008CDB25 /* SessionStatusLiveExtension.appex */, - D2F32FAD2E90B26500B1BC56 /* OpenClimbTests.xctest */, + D2F32FAD2E90B26500B1BC56 /* AscentlyTests.xctest */, ); name = Products; sourceTree = ""; @@ -160,9 +160,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - D24C19672E75002A0045894C /* OpenClimb */ = { + D24C19672E75002A0045894C /* Ascently */ = { isa = PBXNativeTarget; - buildConfigurationList = D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "OpenClimb" */; + buildConfigurationList = D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "Ascently" */; buildPhases = ( D24C19642E75002A0045894C /* Sources */, D24C19652E75002A0045894C /* Frameworks */, @@ -175,18 +175,18 @@ D2FE949F2E78FEE1008CDB25 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( - D24C196A2E75002A0045894C /* OpenClimb */, + D24C196A2E75002A0045894C /* Ascently */, ); - name = OpenClimb; + name = Ascently; packageProductDependencies = ( ); - productName = OpenClimb; - productReference = D24C19682E75002A0045894C /* OpenClimb.app */; + productName = Ascently; + productReference = D24C19682E75002A0045894C /* Ascently.app */; productType = "com.apple.product-type.application"; }; - D2F32FAC2E90B26500B1BC56 /* OpenClimbTests */ = { + D2F32FAC2E90B26500B1BC56 /* AscentlyTests */ = { isa = PBXNativeTarget; - buildConfigurationList = D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "OpenClimbTests" */; + buildConfigurationList = D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "AscentlyTests" */; buildPhases = ( D2F32FA92E90B26500B1BC56 /* Sources */, D2F32FAA2E90B26500B1BC56 /* Frameworks */, @@ -198,13 +198,13 @@ D2F32FB22E90B26500B1BC56 /* PBXTargetDependency */, ); fileSystemSynchronizedGroups = ( - D2F32FAE2E90B26500B1BC56 /* OpenClimbTests */, + D2F32FAE2E90B26500B1BC56 /* AscentlyTests */, ); - name = OpenClimbTests; + name = AscentlyTests; packageProductDependencies = ( ); - productName = OpenClimbTests; - productReference = D2F32FAD2E90B26500B1BC56 /* OpenClimbTests.xctest */; + productName = AscentlyTests; + productReference = D2F32FAD2E90B26500B1BC56 /* AscentlyTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; D2FE948A2E78FEE0008CDB25 /* SessionStatusLiveExtension */ = { @@ -251,7 +251,7 @@ }; }; }; - buildConfigurationList = D24C19632E75002A0045894C /* Build configuration list for PBXProject "OpenClimb" */; + buildConfigurationList = D24C19632E75002A0045894C /* Build configuration list for PBXProject "Ascently" */; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -265,9 +265,9 @@ projectDirPath = ""; projectRoot = ""; targets = ( - D24C19672E75002A0045894C /* OpenClimb */, + D24C19672E75002A0045894C /* Ascently */, D2FE948A2E78FEE0008CDB25 /* SessionStatusLiveExtension */, - D2F32FAC2E90B26500B1BC56 /* OpenClimbTests */, + D2F32FAC2E90B26500B1BC56 /* AscentlyTests */, ); }; /* End PBXProject section */ @@ -323,7 +323,7 @@ /* Begin PBXTargetDependency section */ D2F32FB22E90B26500B1BC56 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = D24C19672E75002A0045894C /* OpenClimb */; + target = D24C19672E75002A0045894C /* Ascently */; targetProxy = D2F32FB12E90B26500B1BC56 /* PBXContainerItemProxy */; }; D2FE949F2E78FEE1008CDB25 /* PBXTargetDependency */ = { @@ -462,7 +462,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = OpenClimb/OpenClimb.entitlements; + CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 25; @@ -470,12 +470,12 @@ DRIVERKIT_DEPLOYMENT_TARGET = 24.6; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = OpenClimb/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = OpenClimb; + INFOPLIST_FILE = Ascently/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Ascently; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; - INFOPLIST_KEY_NSCameraUsageDescription = "OpenClimb needs camera access to take photos of climbing problems."; - INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "OpenClimb needs access to your photo library to save and display climbing problem images."; + INFOPLIST_KEY_NSCameraUsageDescription = "Ascently needs camera access to take photos of climbing problems."; + INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Ascently needs access to your photo library to save and display climbing problem images."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -487,8 +487,8 @@ "@executable_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 15.6; - MARKETING_VERSION = 1.4.0; - PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb; + MARKETING_VERSION = 2.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -510,7 +510,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_ENTITLEMENTS = OpenClimb/OpenClimb.entitlements; + CODE_SIGN_ENTITLEMENTS = Ascently/Ascently.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 25; @@ -518,12 +518,12 @@ DRIVERKIT_DEPLOYMENT_TARGET = 24.6; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = OpenClimb/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = OpenClimb; + INFOPLIST_FILE = Ascently/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Ascently; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports"; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; - INFOPLIST_KEY_NSCameraUsageDescription = "OpenClimb needs camera access to take photos of climbing problems."; - INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "OpenClimb needs access to your photo library to save and display climbing problem images."; + INFOPLIST_KEY_NSCameraUsageDescription = "Ascently needs camera access to take photos of climbing problems."; + INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Ascently needs access to your photo library to save and display climbing problem images."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -535,8 +535,8 @@ "@executable_path/Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 15.6; - MARKETING_VERSION = 1.4.0; - PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb; + MARKETING_VERSION = 2.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -562,7 +562,7 @@ DEVELOPMENT_TEAM = 4BC9Y2LL4B; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.OpenClimb.Watch.OpenClimbTests; + PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.OpenClimb.Watch.AscentlyTests; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; SWIFT_APPROACHABLE_CONCURRENCY = YES; @@ -570,7 +570,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OpenClimb.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OpenClimb"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Ascently.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OpenClimb"; }; name = Debug; }; @@ -583,7 +583,7 @@ DEVELOPMENT_TEAM = 4BC9Y2LL4B; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.OpenClimb.Watch.OpenClimbTests; + PRODUCT_BUNDLE_IDENTIFIER = com.atri.dad.OpenClimb.Watch.AscentlyTests; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; SWIFT_APPROACHABLE_CONCURRENCY = YES; @@ -591,7 +591,7 @@ SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/OpenClimb.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OpenClimb"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Ascently.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/OpenClimb"; }; name = Release; }; @@ -602,7 +602,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = 4BC9Y2LL4B; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SessionStatusLive/Info.plist; @@ -613,8 +613,8 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.4.0; - PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb.SessionStatusLive; + MARKETING_VERSION = 2.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -632,7 +632,7 @@ ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 25; + CURRENT_PROJECT_VERSION = 26; DEVELOPMENT_TEAM = 4BC9Y2LL4B; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = SessionStatusLive/Info.plist; @@ -643,8 +643,8 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 1.4.0; - PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb.SessionStatusLive; + MARKETING_VERSION = 2.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; @@ -658,7 +658,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - D24C19632E75002A0045894C /* Build configuration list for PBXProject "OpenClimb" */ = { + D24C19632E75002A0045894C /* Build configuration list for PBXProject "Ascently" */ = { isa = XCConfigurationList; buildConfigurations = ( D24C19712E75002A0045894C /* Debug */, @@ -667,7 +667,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "OpenClimb" */ = { + D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "Ascently" */ = { isa = XCConfigurationList; buildConfigurations = ( D24C19742E75002A0045894C /* Debug */, @@ -676,7 +676,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "OpenClimbTests" */ = { + D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "AscentlyTests" */ = { isa = XCConfigurationList; buildConfigurations = ( D2F32FB32E90B26500B1BC56 /* Debug */, diff --git a/ios/OpenClimb.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Ascently.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from ios/OpenClimb.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to ios/Ascently.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/ios/OpenClimb.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Ascently.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings similarity index 100% rename from ios/OpenClimb.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings rename to ios/Ascently.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings diff --git a/ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/IDEFindNavigatorScopes.plist b/ios/Ascently.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/IDEFindNavigatorScopes.plist similarity index 100% rename from ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/IDEFindNavigatorScopes.plist rename to ios/Ascently.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/IDEFindNavigatorScopes.plist diff --git a/ios/Ascently.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate b/ios/Ascently.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..a9d5978 Binary files /dev/null and b/ios/Ascently.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/WorkspaceSettings.xcsettings b/ios/Ascently.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/WorkspaceSettings.xcsettings similarity index 100% rename from ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/WorkspaceSettings.xcsettings rename to ios/Ascently.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/WorkspaceSettings.xcsettings diff --git a/ios/OpenClimb.xcodeproj/xcshareddata/xcschemes/OpenClimb.xcscheme b/ios/Ascently.xcodeproj/xcshareddata/xcschemes/OpenClimb.xcscheme similarity index 80% rename from ios/OpenClimb.xcodeproj/xcshareddata/xcschemes/OpenClimb.xcscheme rename to ios/Ascently.xcodeproj/xcshareddata/xcschemes/OpenClimb.xcscheme index e330960..7c887db 100644 --- a/ios/OpenClimb.xcodeproj/xcshareddata/xcschemes/OpenClimb.xcscheme +++ b/ios/Ascently.xcodeproj/xcshareddata/xcschemes/OpenClimb.xcscheme @@ -15,9 +15,9 @@ + BuildableName = "Ascently.app" + BlueprintName = "Ascently" + ReferencedContainer = "container:Ascently.xcodeproj"> @@ -34,9 +34,9 @@ + BuildableName = "AscentlyTests.xctest" + BlueprintName = "AscentlyTests" + ReferencedContainer = "container:Ascently.xcodeproj"> @@ -56,9 +56,9 @@ + BuildableName = "Ascently.app" + BlueprintName = "Ascently" + ReferencedContainer = "container:Ascently.xcodeproj"> @@ -73,9 +73,9 @@ + BuildableName = "Ascently.app" + BlueprintName = "Ascently" + ReferencedContainer = "container:Ascently.xcodeproj"> diff --git a/ios/OpenClimb.xcodeproj/xcshareddata/xcschemes/SessionStatusLiveExtension.xcscheme b/ios/Ascently.xcodeproj/xcshareddata/xcschemes/SessionStatusLiveExtension.xcscheme similarity index 85% rename from ios/OpenClimb.xcodeproj/xcshareddata/xcschemes/SessionStatusLiveExtension.xcscheme rename to ios/Ascently.xcodeproj/xcshareddata/xcschemes/SessionStatusLiveExtension.xcscheme index b074f3a..5069e35 100644 --- a/ios/OpenClimb.xcodeproj/xcshareddata/xcschemes/SessionStatusLiveExtension.xcscheme +++ b/ios/Ascently.xcodeproj/xcshareddata/xcschemes/SessionStatusLiveExtension.xcscheme @@ -19,7 +19,7 @@ BlueprintIdentifier = "D2FE948A2E78FEE0008CDB25" BuildableName = "SessionStatusLiveExtension.appex" BlueprintName = "SessionStatusLiveExtension" - ReferencedContainer = "container:OpenClimb.xcodeproj"> + ReferencedContainer = "container:Ascently.xcodeproj"> + BuildableName = "Ascently.app" + BlueprintName = "Ascently" + ReferencedContainer = "container:Ascently.xcodeproj"> @@ -51,9 +51,9 @@ + BuildableName = "AscentlyTests.xctest" + BlueprintName = "AscentlyTests" + ReferencedContainer = "container:Ascently.xcodeproj"> @@ -75,9 +75,9 @@ + BuildableName = "Ascently.app" + BlueprintName = "Ascently" + ReferencedContainer = "container:Ascently.xcodeproj"> @@ -111,9 +111,9 @@ + BuildableName = "Ascently.app" + BlueprintName = "Ascently" + ReferencedContainer = "container:Ascently.xcodeproj"> diff --git a/ios/OpenClimb.xcodeproj/xcuserdata/atridad.xcuserdatad/xcschemes/xcschememanagement.plist b/ios/Ascently.xcodeproj/xcuserdata/atridad.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 80% rename from ios/OpenClimb.xcodeproj/xcuserdata/atridad.xcuserdatad/xcschemes/xcschememanagement.plist rename to ios/Ascently.xcodeproj/xcuserdata/atridad.xcuserdatad/xcschemes/xcschememanagement.plist index 7dfcbe0..dfb4a31 100644 --- a/ios/OpenClimb.xcodeproj/xcuserdata/atridad.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/ios/Ascently.xcodeproj/xcuserdata/atridad.xcuserdatad/xcschemes/xcschememanagement.plist @@ -4,7 +4,12 @@ SchemeUserState - OpenClimb.xcscheme_^#shared#^_ + AscentlyTests.xcscheme_^#shared#^_ + + orderHint + 2 + + Ascently.xcscheme_^#shared#^_ orderHint 1 diff --git a/ios/OpenClimb/OpenClimb.entitlements b/ios/Ascently/Ascently.entitlements similarity index 88% rename from ios/OpenClimb/OpenClimb.entitlements rename to ios/Ascently/Ascently.entitlements index 7810965..b00abdd 100644 --- a/ios/OpenClimb/OpenClimb.entitlements +++ b/ios/Ascently/Ascently.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.atridad.OpenClimb + group.com.atridad.Ascently com.apple.developer.healthkit diff --git a/ios/OpenClimb/OpenClimbApp.swift b/ios/Ascently/AscentlyApp.swift similarity index 80% rename from ios/OpenClimb/OpenClimbApp.swift rename to ios/Ascently/AscentlyApp.swift index b1cab24..1d10d71 100644 --- a/ios/OpenClimb/OpenClimbApp.swift +++ b/ios/Ascently/AscentlyApp.swift @@ -1,8 +1,7 @@ - import SwiftUI @main -struct OpenClimbApp: App { +struct AscentlyApp: App { var body: some Scene { WindowGroup { ContentView() diff --git a/ios/OpenClimb/Assets.xcassets/AccentColor.colorset/Contents.json b/ios/Ascently/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AccentColor.colorset/Contents.json rename to ios/Ascently/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Ascently/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/Contents.json rename to ios/Ascently/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png rename to ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png diff --git a/ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_1024_dark.png b/ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_1024_dark.png similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_1024_dark.png rename to ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_1024_dark.png diff --git a/ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_1024_tinted.png b/ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_1024_tinted.png similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_1024_tinted.png rename to ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_1024_tinted.png diff --git a/ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_dark_template.svg b/ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_dark_template.svg similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_dark_template.svg rename to ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_dark_template.svg diff --git a/ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_light_template.svg b/ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_light_template.svg similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_light_template.svg rename to ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_light_template.svg diff --git a/ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_tinted_template.svg b/ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_tinted_template.svg similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppIcon.appiconset/app_icon_tinted_template.svg rename to ios/Ascently/Assets.xcassets/AppIcon.appiconset/app_icon_tinted_template.svg diff --git a/ios/OpenClimb/Assets.xcassets/AppLogo.imageset/Contents.json b/ios/Ascently/Assets.xcassets/AppLogo.imageset/Contents.json similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppLogo.imageset/Contents.json rename to ios/Ascently/Assets.xcassets/AppLogo.imageset/Contents.json diff --git a/ios/OpenClimb/Assets.xcassets/AppLogo.imageset/app_logo_256.png b/ios/Ascently/Assets.xcassets/AppLogo.imageset/app_logo_256.png similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppLogo.imageset/app_logo_256.png rename to ios/Ascently/Assets.xcassets/AppLogo.imageset/app_logo_256.png diff --git a/ios/OpenClimb/Assets.xcassets/AppLogo.imageset/app_logo_256_dark.png b/ios/Ascently/Assets.xcassets/AppLogo.imageset/app_logo_256_dark.png similarity index 100% rename from ios/OpenClimb/Assets.xcassets/AppLogo.imageset/app_logo_256_dark.png rename to ios/Ascently/Assets.xcassets/AppLogo.imageset/app_logo_256_dark.png diff --git a/ios/OpenClimb/Assets.xcassets/Contents.json b/ios/Ascently/Assets.xcassets/Contents.json similarity index 100% rename from ios/OpenClimb/Assets.xcassets/Contents.json rename to ios/Ascently/Assets.xcassets/Contents.json diff --git a/ios/OpenClimb/Components/AsyncImageView.swift b/ios/Ascently/Components/AsyncImageView.swift similarity index 100% rename from ios/OpenClimb/Components/AsyncImageView.swift rename to ios/Ascently/Components/AsyncImageView.swift diff --git a/ios/OpenClimb/Components/CameraImagePicker.swift b/ios/Ascently/Components/CameraImagePicker.swift similarity index 100% rename from ios/OpenClimb/Components/CameraImagePicker.swift rename to ios/Ascently/Components/CameraImagePicker.swift diff --git a/ios/OpenClimb/Components/PhotoOptionSheet.swift b/ios/Ascently/Components/PhotoOptionSheet.swift similarity index 100% rename from ios/OpenClimb/Components/PhotoOptionSheet.swift rename to ios/Ascently/Components/PhotoOptionSheet.swift diff --git a/ios/OpenClimb/ContentView.swift b/ios/Ascently/ContentView.swift similarity index 100% rename from ios/OpenClimb/ContentView.swift rename to ios/Ascently/ContentView.swift diff --git a/ios/OpenClimb/Info.plist b/ios/Ascently/Info.plist similarity index 100% rename from ios/OpenClimb/Info.plist rename to ios/Ascently/Info.plist diff --git a/ios/OpenClimb/Models/ActivityAttributes.swift b/ios/Ascently/Models/ActivityAttributes.swift similarity index 100% rename from ios/OpenClimb/Models/ActivityAttributes.swift rename to ios/Ascently/Models/ActivityAttributes.swift diff --git a/ios/OpenClimb/Models/BackupFormat.swift b/ios/Ascently/Models/BackupFormat.swift similarity index 99% rename from ios/OpenClimb/Models/BackupFormat.swift rename to ios/Ascently/Models/BackupFormat.swift index 4691651..9665661 100644 --- a/ios/OpenClimb/Models/BackupFormat.swift +++ b/ios/Ascently/Models/BackupFormat.swift @@ -5,7 +5,7 @@ import Foundation // MARK: - Backup Format Specification v2.0 -/// Root structure for OpenClimb backup data +/// Root structure for Ascently backup data struct DeletedItem: Codable, Hashable { let id: String let type: String // "gym", "problem", "session", "attempt" diff --git a/ios/OpenClimb/Models/DataModels.swift b/ios/Ascently/Models/DataModels.swift similarity index 100% rename from ios/OpenClimb/Models/DataModels.swift rename to ios/Ascently/Models/DataModels.swift diff --git a/ios/OpenClimb/Services/HealthKitService.swift b/ios/Ascently/Services/HealthKitService.swift similarity index 100% rename from ios/OpenClimb/Services/HealthKitService.swift rename to ios/Ascently/Services/HealthKitService.swift diff --git a/ios/OpenClimb/Services/SyncService.swift b/ios/Ascently/Services/SyncService.swift similarity index 99% rename from ios/OpenClimb/Services/SyncService.swift rename to ios/Ascently/Services/SyncService.swift index 3460f46..72b56bd 100644 --- a/ios/OpenClimb/Services/SyncService.swift +++ b/ios/Ascently/Services/SyncService.swift @@ -501,7 +501,7 @@ class SyncService: ObservableObject { // Update local deletions with merged list dataManager.clearDeletedItems() if let data = try? JSONEncoder().encode(uniqueDeletions) { - UserDefaults.standard.set(data, forKey: "openclimb_deleted_items") + UserDefaults.standard.set(data, forKey: "ascently_deleted_items") } // Upload merged data back to server @@ -648,7 +648,7 @@ class SyncService: ObservableObject { // Import deletion records to prevent future resurrections dataManager.clearDeletedItems() if let data = try? JSONEncoder().encode(backup.deletedItems) { - UserDefaults.standard.set(data, forKey: "openclimb_deleted_items") + UserDefaults.standard.set(data, forKey: "ascently_deleted_items") print("iOS IMPORT: Imported \(backup.deletedItems.count) deletion records") } diff --git a/ios/OpenClimb/Utils/AppIconHelper.swift b/ios/Ascently/Utils/AppIconHelper.swift similarity index 100% rename from ios/OpenClimb/Utils/AppIconHelper.swift rename to ios/Ascently/Utils/AppIconHelper.swift diff --git a/ios/OpenClimb/Utils/DataStateManager.swift b/ios/Ascently/Utils/DataStateManager.swift similarity index 95% rename from ios/OpenClimb/Utils/DataStateManager.swift rename to ios/Ascently/Utils/DataStateManager.swift index e7ff5ea..69c05b4 100644 --- a/ios/OpenClimb/Utils/DataStateManager.swift +++ b/ios/Ascently/Utils/DataStateManager.swift @@ -9,8 +9,8 @@ class DataStateManager { private let userDefaults = UserDefaults.standard private enum Keys { - static let lastModified = "openclimb_data_last_modified" - static let initialized = "openclimb_data_state_initialized" + static let lastModified = "ascently_data_last_modified" + static let initialized = "ascently_data_state_initialized" } static let shared = DataStateManager() diff --git a/ios/OpenClimb/Utils/IconTestView.swift b/ios/Ascently/Utils/IconTestView.swift similarity index 100% rename from ios/OpenClimb/Utils/IconTestView.swift rename to ios/Ascently/Utils/IconTestView.swift diff --git a/ios/OpenClimb/Utils/ImageManager.swift b/ios/Ascently/Utils/ImageManager.swift similarity index 93% rename from ios/OpenClimb/Utils/ImageManager.swift rename to ios/Ascently/Utils/ImageManager.swift index 80bdcbb..2edae1a 100644 --- a/ios/OpenClimb/Utils/ImageManager.swift +++ b/ios/Ascently/Utils/ImageManager.swift @@ -8,13 +8,17 @@ class ImageManager { private let thumbnailCache = NSCache() private let fileManager = FileManager.default - private let appSupportDirectoryName = "OpenClimb" + private let appSupportDirectoryName = "Ascently" private let imagesDirectoryName = "Images" private let backupDirectoryName = "ImageBackups" private let migrationStateFile = "migration_state.json" private let migrationLockFile = "migration.lock" + // Legacy directory name for migration + private let legacyAppSupportDirectoryName = "OpenClimb" + private init() { + migrateFromOpenClimbDirectoryIfNeeded() createDirectoriesIfNeeded() // Debug-safe initialization with extra checks @@ -58,6 +62,52 @@ class ImageManager { legacyDocumentsDirectory.appendingPathComponent("OpenClimbImages") } + /// Legacy OpenClimb app support directory for migration + private var legacyOpenClimbAppSupportDirectory: URL? { + guard + let appSupportBase = fileManager.urls( + for: .applicationSupportDirectory, in: .userDomainMask + ).first + else { + return nil + } + return appSupportBase.appendingPathComponent(legacyAppSupportDirectoryName) + } + + /// Migrate images from OpenClimb directory to Ascently directory + private func migrateFromOpenClimbDirectoryIfNeeded() { + guard let legacyDir = legacyOpenClimbAppSupportDirectory, + fileManager.fileExists(atPath: legacyDir.path), + !fileManager.fileExists(atPath: appSupportDirectory.path) + else { + return + } + + print("🔄 Migrating images from OpenClimb to Ascently directory...") + + do { + // Create parent directory if needed + try fileManager.createDirectory( + at: appSupportDirectory.deletingLastPathComponent(), + withIntermediateDirectories: true, + attributes: nil) + + // Move the entire directory + try fileManager.moveItem(at: legacyDir, to: appSupportDirectory) + print("Successfully migrated image directory from OpenClimb to Ascently") + } catch { + print("❌ Failed to migrate image directory: \(error)") + // If move fails, try to copy instead + do { + try fileManager.copyItem(at: legacyDir, to: appSupportDirectory) + print("Successfully copied image directory from OpenClimb to Ascently") + // Don't remove the old directory in case of issues + } catch { + print("❌ Failed to copy image directory: \(error)") + } + } + } + var legacyImportImagesDirectory: URL { legacyDocumentsDirectory.appendingPathComponent("images") } @@ -671,7 +721,7 @@ class ImageManager { let previousDir = findPreviousAppSupportImages() print( """ - OpenClimb Image Storage: + Ascently Image Storage: - App Support: \(appSupportDirectory.path) - Images: \(imagesDirectory.path) (\(info.primaryCount) files) - Backups: \(backupDirectory.path) (\(info.backupCount) files) @@ -842,8 +892,9 @@ class ImageManager { continue } - // Check if it's an OpenClimb directory but not the current one - if url.lastPathComponent.contains("OpenClimb") + // Check if it's an OpenClimb or Ascently directory but not the current one + if (url.lastPathComponent.contains("OpenClimb") + || url.lastPathComponent.contains("Ascently")) && url.path != appSupportDirectory.path { let imagesDir = url.appendingPathComponent(imagesDirectoryName) diff --git a/ios/OpenClimb/Utils/ImageNamingUtils.swift b/ios/Ascently/Utils/ImageNamingUtils.swift similarity index 100% rename from ios/OpenClimb/Utils/ImageNamingUtils.swift rename to ios/Ascently/Utils/ImageNamingUtils.swift diff --git a/ios/OpenClimb/Utils/OrientationAwareImage.swift b/ios/Ascently/Utils/OrientationAwareImage.swift similarity index 100% rename from ios/OpenClimb/Utils/OrientationAwareImage.swift rename to ios/Ascently/Utils/OrientationAwareImage.swift diff --git a/ios/OpenClimb/Utils/ZipUtils.swift b/ios/Ascently/Utils/ZipUtils.swift similarity index 99% rename from ios/OpenClimb/Utils/ZipUtils.swift rename to ios/Ascently/Utils/ZipUtils.swift index 64d4fbd..c64647f 100644 --- a/ios/OpenClimb/Utils/ZipUtils.swift +++ b/ios/Ascently/Utils/ZipUtils.swift @@ -199,8 +199,8 @@ struct ZipUtils { referencedImagePaths: Set ) -> String { return """ - OpenClimb Export Metadata - ======================= + Ascently Export Metadata + ======================== Export Date: \(exportData.exportedAt) Gyms: \(exportData.gyms.count) Problems: \(exportData.problems.count) diff --git a/ios/OpenClimb/ViewModels/ClimbingDataManager.swift b/ios/Ascently/ViewModels/ClimbingDataManager.swift similarity index 93% rename from ios/OpenClimb/ViewModels/ClimbingDataManager.swift rename to ios/Ascently/ViewModels/ClimbingDataManager.swift index 79941cf..81d9a9e 100644 --- a/ios/OpenClimb/ViewModels/ClimbingDataManager.swift +++ b/ios/Ascently/ViewModels/ClimbingDataManager.swift @@ -25,9 +25,12 @@ class ClimbingDataManager: ObservableObject { @Published var successMessage: String? private let userDefaults = UserDefaults.standard - private let sharedUserDefaults = UserDefaults(suiteName: "group.com.atridad.OpenClimb") + private let sharedUserDefaults = UserDefaults(suiteName: "group.com.atridad.Ascently") private let encoder = JSONEncoder() private let decoder = JSONDecoder() + + // Flag to track if migration has been performed + private let migrationKey = "ascently_data_migrated_from_openclimb" nonisolated(unsafe) private var liveActivityObserver: NSObjectProtocol? nonisolated(unsafe) private var migrationObserver: NSObjectProtocol? @@ -37,6 +40,16 @@ class ClimbingDataManager: ObservableObject { @Published var isSyncing = false private enum Keys { + static let gyms = "ascently_gyms" + static let problems = "ascently_problems" + static let sessions = "ascently_sessions" + static let attempts = "ascently_attempts" + static let activeSession = "ascently_active_session" + static let deletedItems = "ascently_deleted_items" + } + + // Legacy keys for migration + private enum LegacyKeys { static let gyms = "openclimb_gyms" static let problems = "openclimb_problems" static let sessions = "openclimb_sessions" @@ -68,6 +81,7 @@ class ClimbingDataManager: ObservableObject { init() { _ = ImageManager.shared + migrateFromOpenClimbIfNeeded() loadAllData() setupLiveActivityNotifications() setupMigrationNotifications() @@ -94,6 +108,74 @@ class ClimbingDataManager: ObservableObject { } } + /// Migrate data from OpenClimb keys to Ascently keys + private func migrateFromOpenClimbIfNeeded() { + // Check if migration has already been performed + if userDefaults.bool(forKey: migrationKey) { + return + } + + print("Starting migration from OpenClimb to Ascently keys...") + var migrationCount = 0 + + // Migrate each data type if it exists in old format but not in new format + let migrations = [ + (LegacyKeys.gyms, Keys.gyms), + (LegacyKeys.problems, Keys.problems), + (LegacyKeys.sessions, Keys.sessions), + (LegacyKeys.attempts, Keys.attempts), + (LegacyKeys.activeSession, Keys.activeSession), + (LegacyKeys.deletedItems, Keys.deletedItems), + ] + + for (oldKey, newKey) in migrations { + if let oldData = userDefaults.data(forKey: oldKey), + userDefaults.data(forKey: newKey) == nil + { + userDefaults.set(oldData, forKey: newKey) + userDefaults.removeObject(forKey: oldKey) + migrationCount += 1 + print("✅ Migrated: \(oldKey) → \(newKey)") + } + } + + // Also migrate shared UserDefaults for widgets + if let sharedDefaults = sharedUserDefaults { + for (oldKey, newKey) in migrations { + if let oldData = sharedDefaults.data(forKey: oldKey), + sharedDefaults.data(forKey: newKey) == nil + { + sharedDefaults.set(oldData, forKey: newKey) + sharedDefaults.removeObject(forKey: oldKey) + print("✅ Migrated shared: \(oldKey) → \(newKey)") + } + } + } + + // Migrate DataStateManager keys + let legacyDataStateKey = "openclimb_data_last_modified" + let newDataStateKey = "ascently_data_last_modified" + if let lastModified = userDefaults.string(forKey: legacyDataStateKey), + userDefaults.string(forKey: newDataStateKey) == nil + { + userDefaults.set(lastModified, forKey: newDataStateKey) + userDefaults.removeObject(forKey: legacyDataStateKey) + migrationCount += 1 + print("✅ Migrated data state timestamp") + } + + // Mark migration as completed + userDefaults.set(true, forKey: migrationKey) + + if migrationCount > 0 { + print( + "Migration completed! Migrated \(migrationCount) data items from OpenClimb to Ascently" + ) + } else { + print("No OpenClimb data found to migrate") + } + } + private func loadAllData() { loadGyms() loadProblems() diff --git a/ios/OpenClimb/ViewModels/LiveActivityManager.swift b/ios/Ascently/ViewModels/LiveActivityManager.swift similarity index 100% rename from ios/OpenClimb/ViewModels/LiveActivityManager.swift rename to ios/Ascently/ViewModels/LiveActivityManager.swift diff --git a/ios/OpenClimb/Views/AddEdit/AddAttemptView.swift b/ios/Ascently/Views/AddEdit/AddAttemptView.swift similarity index 100% rename from ios/OpenClimb/Views/AddEdit/AddAttemptView.swift rename to ios/Ascently/Views/AddEdit/AddAttemptView.swift diff --git a/ios/OpenClimb/Views/AddEdit/AddEditGymView.swift b/ios/Ascently/Views/AddEdit/AddEditGymView.swift similarity index 100% rename from ios/OpenClimb/Views/AddEdit/AddEditGymView.swift rename to ios/Ascently/Views/AddEdit/AddEditGymView.swift diff --git a/ios/OpenClimb/Views/AddEdit/AddEditProblemView.swift b/ios/Ascently/Views/AddEdit/AddEditProblemView.swift similarity index 100% rename from ios/OpenClimb/Views/AddEdit/AddEditProblemView.swift rename to ios/Ascently/Views/AddEdit/AddEditProblemView.swift diff --git a/ios/OpenClimb/Views/AddEdit/AddEditSessionView.swift b/ios/Ascently/Views/AddEdit/AddEditSessionView.swift similarity index 100% rename from ios/OpenClimb/Views/AddEdit/AddEditSessionView.swift rename to ios/Ascently/Views/AddEdit/AddEditSessionView.swift diff --git a/ios/OpenClimb/Views/AnalyticsView.swift b/ios/Ascently/Views/AnalyticsView.swift similarity index 100% rename from ios/OpenClimb/Views/AnalyticsView.swift rename to ios/Ascently/Views/AnalyticsView.swift diff --git a/ios/OpenClimb/Views/Detail/GymDetailView.swift b/ios/Ascently/Views/Detail/GymDetailView.swift similarity index 100% rename from ios/OpenClimb/Views/Detail/GymDetailView.swift rename to ios/Ascently/Views/Detail/GymDetailView.swift diff --git a/ios/OpenClimb/Views/Detail/ProblemDetailView.swift b/ios/Ascently/Views/Detail/ProblemDetailView.swift similarity index 100% rename from ios/OpenClimb/Views/Detail/ProblemDetailView.swift rename to ios/Ascently/Views/Detail/ProblemDetailView.swift diff --git a/ios/OpenClimb/Views/Detail/SessionDetailView.swift b/ios/Ascently/Views/Detail/SessionDetailView.swift similarity index 100% rename from ios/OpenClimb/Views/Detail/SessionDetailView.swift rename to ios/Ascently/Views/Detail/SessionDetailView.swift diff --git a/ios/OpenClimb/Views/GymsView.swift b/ios/Ascently/Views/GymsView.swift similarity index 100% rename from ios/OpenClimb/Views/GymsView.swift rename to ios/Ascently/Views/GymsView.swift diff --git a/ios/OpenClimb/Views/LiveActivityDebugView.swift b/ios/Ascently/Views/LiveActivityDebugView.swift similarity index 100% rename from ios/OpenClimb/Views/LiveActivityDebugView.swift rename to ios/Ascently/Views/LiveActivityDebugView.swift diff --git a/ios/OpenClimb/Views/ProblemsView.swift b/ios/Ascently/Views/ProblemsView.swift similarity index 100% rename from ios/OpenClimb/Views/ProblemsView.swift rename to ios/Ascently/Views/ProblemsView.swift diff --git a/ios/OpenClimb/Views/SessionsView.swift b/ios/Ascently/Views/SessionsView.swift similarity index 100% rename from ios/OpenClimb/Views/SessionsView.swift rename to ios/Ascently/Views/SessionsView.swift diff --git a/ios/OpenClimb/Views/SettingsView.swift b/ios/Ascently/Views/SettingsView.swift similarity index 99% rename from ios/OpenClimb/Views/SettingsView.swift rename to ios/Ascently/Views/SettingsView.swift index e11efb9..5cbdd3a 100644 --- a/ios/OpenClimb/Views/SettingsView.swift +++ b/ios/Ascently/Views/SettingsView.swift @@ -263,7 +263,7 @@ struct AppInfoSection: View { .resizable() .frame(width: 24, height: 24) VStack(alignment: .leading) { - Text("OpenClimb") + Text("Ascently") .font(.headline) Text("Track your climbing progress") .font(.caption) @@ -332,7 +332,7 @@ struct ExportDataView: View { ShareLink( item: fileURL, preview: SharePreview( - "OpenClimb Data Export", + "Ascently Data Export", image: Image("AppLogo")) ) { Label("Share Data", systemImage: "square.and.arrow.up") @@ -385,7 +385,7 @@ struct ExportDataView: View { let isoString = formatter.string(from: Date()) let timestamp = isoString.replacingOccurrences(of: ":", with: "-") .replacingOccurrences(of: ".", with: "-") - let filename = "openclimb_export_\(timestamp).zip" + let filename = "ascently_export_\(timestamp).zip" guard let documentsURL = FileManager.default.urls( diff --git a/ios/OpenClimbTests/OpenClimbTests.swift b/ios/AscentlyTests/AscentlyTests.swift similarity index 99% rename from ios/OpenClimbTests/OpenClimbTests.swift rename to ios/AscentlyTests/AscentlyTests.swift index 104c622..71fbe0f 100644 --- a/ios/OpenClimbTests/OpenClimbTests.swift +++ b/ios/AscentlyTests/AscentlyTests.swift @@ -1,6 +1,6 @@ import XCTest -final class OpenClimbTests: XCTestCase { +final class AscentlyTests: XCTestCase { override func setUpWithError() throws { } diff --git a/ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate b/ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 4b2b45d..0000000 Binary files a/ios/OpenClimb.xcodeproj/project.xcworkspace/xcuserdata/atridad.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/ios/README.md b/ios/README.md index 53b59c6..67d41bc 100644 --- a/ios/README.md +++ b/ios/README.md @@ -1,10 +1,10 @@ -# OpenClimb for iOS +# Ascently for iOS -The native iOS, watchOS, and widget client for OpenClimb, built with Swift and SwiftUI. +The native iOS, watchOS, and widget client for Ascently, built with Swift and SwiftUI. ## Project Structure -This is a standard Xcode project. The main app code is in the `OpenClimb/` directory. +This is a standard Xcode project. The main app code is in the `Ascently/` directory. - `Models/`: Swift `Codable` models (`Problem`, `Gym`, `ClimbSession`) that match the Android app. - `ViewModels/`: App state and logic. `ClimbingDataManager` is the core here, handling data with SwiftData. @@ -16,8 +16,7 @@ This is a standard Xcode project. The main app code is in the `OpenClimb/` direc ## Other Targets -- `OpenClimbWatch/`: The watchOS app for tracking sessions. - `ClimbingActivityWidget/`: A home screen widget. - `SessionStatusLive/`: A Live Activity for the lock screen. -The app is built to be offline-first. All data is stored locally on your device and works without an internet connection. \ No newline at end of file +The app is built to be offline-first. All data is stored locally on your device and works without an internet connection. diff --git a/ios/SessionStatusLive/SessionStatusLive.swift b/ios/SessionStatusLive/SessionStatusLive.swift index 89bc119..afdad76 100644 --- a/ios/SessionStatusLive/SessionStatusLive.swift +++ b/ios/SessionStatusLive/SessionStatusLive.swift @@ -49,10 +49,10 @@ struct ClimbingStatsProvider: TimelineProvider { } private func loadClimbingStats() -> ClimbingStats { - let userDefaults = UserDefaults(suiteName: "group.com.atridad.OpenClimb") + let userDefaults = UserDefaults(suiteName: "group.com.atridad.Ascently") // Load attempts from UserDefaults - guard let attemptsData = userDefaults?.data(forKey: "openclimb_attempts"), + guard let attemptsData = userDefaults?.data(forKey: "ascently_attempts"), let attempts = try? JSONDecoder().decode([WidgetAttempt].self, from: attemptsData) else { return ClimbingStats( @@ -60,11 +60,11 @@ struct ClimbingStatsProvider: TimelineProvider { } // Load sessions for streak calculation - let sessionsData = (userDefaults?.data(forKey: "openclimb_sessions"))! + let sessionsData = (userDefaults?.data(forKey: "ascently_sessions"))! let sessions = (try? JSONDecoder().decode([WidgetSession].self, from: sessionsData)) ?? [] // Load gyms for favorite gym name - let gymsData = (userDefaults?.data(forKey: "openclimb_gyms"))! + let gymsData = (userDefaults?.data(forKey: "ascently_gyms"))! let gyms = (try? JSONDecoder().decode([WidgetGym].self, from: gymsData)) ?? [] let calendar = Calendar.current diff --git a/ios/SessionStatusLive/SessionStatusLiveControl.swift b/ios/SessionStatusLive/SessionStatusLiveControl.swift index 70f5ae6..3471c8f 100644 --- a/ios/SessionStatusLive/SessionStatusLiveControl.swift +++ b/ios/SessionStatusLive/SessionStatusLiveControl.swift @@ -6,7 +6,7 @@ import SwiftUI import WidgetKit struct SessionStatusLiveControl: ControlWidget { - static let kind: String = "com.atridad.OpenClimb.SessionStatusLive" + static let kind: String = "com.atridad.Ascently.SessionStatusLive" var body: some ControlWidgetConfiguration { AppIntentControlConfiguration( diff --git a/ios/SessionStatusLiveExtension.entitlements b/ios/SessionStatusLiveExtension.entitlements index 2630f0c..f207868 100644 --- a/ios/SessionStatusLiveExtension.entitlements +++ b/ios/SessionStatusLiveExtension.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.atridad.OpenClimb + group.com.atridad.Ascently diff --git a/sync/.env.example b/sync/.env.example index f39de10..d8dcb2b 100644 --- a/sync/.env.example +++ b/sync/.env.example @@ -1,6 +1,6 @@ # Required AUTH_TOKEN=your-secure-secret-token-here -IMAGE="git.atri.dad/atridad/openclimb-sync:latest" +IMAGE="git.atri.dad/atridad/ascently-sync:latest" APP_PORT=1337 ROOT_DIR="./data" diff --git a/sync/.gitignore b/sync/.gitignore index 9fc8fde..faab951 100644 --- a/sync/.gitignore +++ b/sync/.gitignore @@ -1,6 +1,6 @@ # Binaries sync-server -openclimb-sync +ascently-sync # Go workspace file go.work diff --git a/sync/README.md b/sync/README.md index 53e3a33..66e1f39 100644 --- a/sync/README.md +++ b/sync/README.md @@ -1,21 +1,21 @@ # Sync Server -A simple Go server for self-hosting your OpenClimb sync data. +A simple Go server for self-hosting your Ascently sync data. ## How It Works -This server is dead simple. It uses a single `openclimb.json` file for your data and a directory for images. The last client to upload wins, overwriting the old data. Authentication is just a static bearer token. +This server is dead simple. It uses a single `ascently.json` file for your data and a directory for images. The last client to upload wins, overwriting the old data. Authentication is just a static bearer token. ## Getting Started 1. Create a `.env` file in this directory: ``` - IMAGE=git.atri.dad/atridad/openclimb-sync:latest + IMAGE=git.atri.dad/atridad/ascently-sync:latest APP_PORT=8080 AUTH_TOKEN=your-super-secret-token - DATA_FILE=/data/openclimb.json + DATA_FILE=/data/ascently.json IMAGES_DIR=/data/images - ROOT_DIR=./openclimb-data + ROOT_DIR=./ascently-data ``` Set `AUTH_TOKEN` to a long, random string. `ROOT_DIR` is where the server will store its data on your machine. @@ -29,8 +29,8 @@ This server is dead simple. It uses a single `openclimb.json` file for your data The API is minimal, just enough for the app to work. All endpoints require an `Authorization: Bearer ` header. -- `GET /sync`: Download `openclimb.json`. -- `POST /sync`: Upload `openclimb.json`. +- `GET /sync`: Download `ascently.json`. +- `POST /sync`: Upload `ascently.json`. - `GET /images/{imageName}`: Download an image. - `POST /images/{imageName}`: Upload an image. diff --git a/sync/docker-compose.yml b/sync/docker-compose.yml index 951b61a..63a1270 100644 --- a/sync/docker-compose.yml +++ b/sync/docker-compose.yml @@ -1,5 +1,5 @@ services: - openclimb-sync: + ascently-sync: image: ${IMAGE} ports: - ${APP_PORT}:8080 diff --git a/sync/go.mod b/sync/go.mod index 3103696..3bb9e3e 100644 --- a/sync/go.mod +++ b/sync/go.mod @@ -1,3 +1,3 @@ -module openclimb-sync +module ascently-sync go 1.25 diff --git a/sync/main.go b/sync/main.go index 9d46eb0..040078a 100644 --- a/sync/main.go +++ b/sync/main.go @@ -358,7 +358,7 @@ func main() { http.HandleFunc("/images/upload", server.handleImageUpload) http.HandleFunc("/images/download", server.handleImageDownload) - fmt.Printf("OpenClimb sync server v%s starting on port %s\n", VERSION, port) + fmt.Printf("Ascently sync server v%s starting on port %s\n", VERSION, port) fmt.Printf("Data file: %s\n", dataFile) fmt.Printf("Images directory: %s\n", imagesDir) fmt.Printf("Health check available at /health\n")