Compare commits

..

2 Commits

Author SHA1 Message Date
d5cf14d466 2.0.0 - Rebranding
All checks were successful
Ascently Docker Deploy / build-and-push (push) Successful in 2m18s
2025-10-13 15:10:54 -06:00
09b4055985 Moved to Ascently
All checks were successful
Ascently Docker Deploy / build-and-push (push) Successful in 2m31s
2025-10-13 14:54:54 -06:00
137 changed files with 796 additions and 489 deletions

View File

@@ -1,4 +1,4 @@
name: OpenClimb Docker Deploy name: Ascently Docker Deploy
on: on:
push: push:
branches: [main] branches: [main]
@@ -34,5 +34,5 @@ jobs:
platforms: linux/amd64 platforms: linux/amd64
push: true push: true
tags: | tags: |
${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/openclimb-sync:${{ github.sha }} ${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/ascently-sync:${{ github.sha }}
${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/openclimb-sync:latest ${{ secrets.REPO_HOST }}/${{ github.repository_owner }}/ascently-sync:latest

View File

@@ -1,13 +1,15 @@
# 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. _Formerly OpenClimb_
This is a FOSS app meant to help climbers track their sessions, routes/problems, and overall progress. This app is offline-first, with an optional sync server and integrations with Apple Health and Health Connect. Its built using Jetpack Compose with Material You support on Android and SwiftUI on iOS.
## Download ## Download
For Android do one of the following: For Android do one of the following:
1. Download the latest APK from the Releases page 1. Download the latest APK from the Releases page
2. [<img src="https://github.com/ImranR98/Obtainium/blob/main/assets/graphics/badge_obtainium.png?raw=true" alt="Obtainium" height="41">](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. [<img src="https://github.com/ImranR98/Obtainium/blob/main/assets/graphics/badge_obtainium.png?raw=true" alt="Obtainium" height="41">](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: For iOS:
@@ -22,12 +24,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: 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 APP_PORT=8080
AUTH_TOKEN=your-secure-auth-token-here AUTH_TOKEN=your-secure-auth-token-here
DATA_FILE=/data/openclimb.json DATA_FILE=/data/ascently.json
IMAGES_DIR=/data/images IMAGES_DIR=/data/images
ROOT_DIR=./openclimb-data ROOT_DIR=./ascently-data
``` ```
2. Use the provided `docker-compose.yml` in the `sync/` directory: 2. Use the provided `docker-compose.yml` in the `sync/` directory:

View File

@@ -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 ## 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. - `data/`: Handles all the app's data.
- `database/`: Room database setup (DAOs, entities). - `database/`: Room database setup (DAOs, entities).

View File

@@ -9,15 +9,15 @@ plugins {
} }
android { android {
namespace = "com.atridad.openclimb" namespace = "com.atridad.ascently"
compileSdk = 36 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "com.atridad.openclimb" applicationId = "com.atridad.ascently"
minSdk = 31 minSdk = 31
targetSdk = 36 targetSdk = 36
versionCode = 39 versionCode = 40
versionName = "1.9.2" versionName = "2.0.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }

View File

@@ -9,11 +9,11 @@ plugins {
} }
android { android {
namespace = "com.atridad.openclimb" namespace = "com.atridad.ascently"
compileSdk = 36 compileSdk = 36
defaultConfig { defaultConfig {
applicationId = "com.atridad.openclimb" applicationId = "com.atridad.ascently"
minSdk = 31 minSdk = 31
targetSdk = 36 targetSdk = 36
versionCode = 27 versionCode = 27

View File

@@ -50,13 +50,13 @@
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.OpenClimb" android:theme="@style/Theme.Ascently"
tools:targetApi="31"> tools:targetApi="31">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/Theme.OpenClimb.Splash"> android:theme="@style/Theme.Ascently.Splash">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb package com.atridad.ascently
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@@ -9,8 +9,9 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import com.atridad.openclimb.ui.OpenClimbApp import com.atridad.ascently.ui.AscentlyApp
import com.atridad.openclimb.ui.theme.OpenClimbTheme import com.atridad.ascently.ui.theme.AscentlyTheme
import com.atridad.ascently.utils.MigrationManager
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private var shortcutAction by mutableStateOf<String?>(null) private var shortcutAction by mutableStateOf<String?>(null)
@@ -23,16 +24,19 @@ class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setTheme(R.style.Theme_OpenClimb) setTheme(R.style.Theme_Ascently)
enableEdgeToEdge() enableEdgeToEdge()
// Perform migration from OpenClimb to Ascently if needed
MigrationManager(this).migrateIfNeeded()
shortcutAction = intent?.action shortcutAction = intent?.action
lastUsedGymId = intent?.getStringExtra("LAST_USED_GYM_ID") lastUsedGymId = intent?.getStringExtra("LAST_USED_GYM_ID")
setContent { setContent {
OpenClimbTheme { AscentlyTheme {
Surface(modifier = Modifier.fillMaxSize()) { Surface(modifier = Modifier.fillMaxSize()) {
OpenClimbApp( AscentlyApp(
shortcutAction = shortcutAction, shortcutAction = shortcutAction,
lastUsedGymId = lastUsedGymId, lastUsedGymId = lastUsedGymId,
onShortcutActionProcessed = { clearShortcutAction() } onShortcutActionProcessed = { clearShortcutAction() }

View File

@@ -1,7 +1,7 @@
package com.atridad.openclimb.data.database package com.atridad.ascently.data.database
import androidx.room.TypeConverter import androidx.room.TypeConverter
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.data.database package com.atridad.ascently.data.database
import android.content.Context import android.content.Context
import androidx.room.Database import androidx.room.Database
@@ -7,8 +7,8 @@ import androidx.room.RoomDatabase
import androidx.room.TypeConverters import androidx.room.TypeConverters
import androidx.room.migration.Migration import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteDatabase
import com.atridad.openclimb.data.database.dao.* import com.atridad.ascently.data.database.dao.*
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
@Database( @Database(
entities = [Gym::class, Problem::class, ClimbSession::class, Attempt::class], entities = [Gym::class, Problem::class, ClimbSession::class, Attempt::class],
@@ -16,7 +16,7 @@ import com.atridad.openclimb.data.model.*
exportSchema = false exportSchema = false
) )
@TypeConverters(Converters::class) @TypeConverters(Converters::class)
abstract class OpenClimbDatabase : RoomDatabase() { abstract class AscentlyDatabase : RoomDatabase() {
abstract fun gymDao(): GymDao abstract fun gymDao(): GymDao
abstract fun problemDao(): ProblemDao abstract fun problemDao(): ProblemDao
@@ -24,7 +24,7 @@ abstract class OpenClimbDatabase : RoomDatabase() {
abstract fun attemptDao(): AttemptDao abstract fun attemptDao(): AttemptDao
companion object { companion object {
@Volatile private var INSTANCE: OpenClimbDatabase? = null @Volatile private var INSTANCE: AscentlyDatabase? = null
val MIGRATION_4_5 = val MIGRATION_4_5 =
object : 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 return INSTANCE
?: synchronized(this) { ?: synchronized(this) {
val instance = val instance =
Room.databaseBuilder( Room.databaseBuilder(
context.applicationContext, context.applicationContext,
OpenClimbDatabase::class.java, AscentlyDatabase::class.java,
"openclimb_database" "ascently_database"
) )
.addMigrations(MIGRATION_4_5, MIGRATION_5_6) .addMigrations(MIGRATION_4_5, MIGRATION_5_6)
.enableMultiInstanceInvalidation() .enableMultiInstanceInvalidation()

View File

@@ -1,8 +1,8 @@
package com.atridad.openclimb.data.database.dao package com.atridad.ascently.data.database.dao
import androidx.room.* import androidx.room.*
import com.atridad.openclimb.data.model.Attempt import com.atridad.ascently.data.model.Attempt
import com.atridad.openclimb.data.model.AttemptResult import com.atridad.ascently.data.model.AttemptResult
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao

View File

@@ -1,8 +1,8 @@
package com.atridad.openclimb.data.database.dao package com.atridad.ascently.data.database.dao
import androidx.room.* import androidx.room.*
import com.atridad.openclimb.data.model.ClimbSession import com.atridad.ascently.data.model.ClimbSession
import com.atridad.openclimb.data.model.SessionStatus import com.atridad.ascently.data.model.SessionStatus
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao

View File

@@ -1,8 +1,8 @@
package com.atridad.openclimb.data.database.dao package com.atridad.ascently.data.database.dao
import androidx.room.* import androidx.room.*
import com.atridad.openclimb.data.model.ClimbType import com.atridad.ascently.data.model.ClimbType
import com.atridad.openclimb.data.model.Gym import com.atridad.ascently.data.model.Gym
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao

View File

@@ -1,8 +1,8 @@
package com.atridad.openclimb.data.database.dao package com.atridad.ascently.data.database.dao
import androidx.room.* import androidx.room.*
import com.atridad.openclimb.data.model.ClimbType import com.atridad.ascently.data.model.ClimbType
import com.atridad.openclimb.data.model.Problem import com.atridad.ascently.data.model.Problem
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
@Dao @Dao

View File

@@ -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 import kotlinx.serialization.Serializable
// Root structure for OpenClimb backup data // Root structure for Ascently backup data
@Serializable @Serializable
data class ClimbDataBackup( data class ClimbDataBackup(
val exportedAt: String, val exportedAt: String,

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.data.health package com.atridad.ascently.data.health
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context 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.HeartRateRecord
import androidx.health.connect.client.records.TotalCaloriesBurnedRecord import androidx.health.connect.client.records.TotalCaloriesBurnedRecord
import androidx.health.connect.client.units.Energy import androidx.health.connect.client.units.Energy
import com.atridad.openclimb.data.model.ClimbSession import com.atridad.ascently.data.model.ClimbSession
import com.atridad.openclimb.data.model.SessionStatus import com.atridad.ascently.data.model.SessionStatus
import com.atridad.openclimb.utils.DateFormatUtils import com.atridad.ascently.utils.DateFormatUtils
import java.time.Duration import java.time.Duration
import java.time.Instant import java.time.Instant
import java.time.ZoneOffset import java.time.ZoneOffset
@@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flow 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. * and other health apps.
*/ */
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
@@ -192,7 +192,7 @@ class HealthConnectManager(private val context: Context) {
} else { } else {
results.add("❌ Health Connect not ready") results.add("❌ Health Connect not ready")
if (!available) results.add("- Health Connect not available on device") 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 (!hasPerms) results.add("- Permissions not granted")
if (!_isCompatible.value) results.add("- API compatibility issues") if (!_isCompatible.value) results.add("- API compatibility issues")
} }

View File

@@ -1,10 +1,10 @@
package com.atridad.openclimb.data.model package com.atridad.ascently.data.model
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.atridad.openclimb.utils.DateFormatUtils import com.atridad.ascently.utils.DateFormatUtils
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable

View File

@@ -1,10 +1,10 @@
package com.atridad.openclimb.data.model package com.atridad.ascently.data.model
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.atridad.openclimb.utils.DateFormatUtils import com.atridad.ascently.utils.DateFormatUtils
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.data.model package com.atridad.ascently.data.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.data.model package com.atridad.ascently.data.model
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,8 +1,8 @@
package com.atridad.openclimb.data.model package com.atridad.ascently.data.model
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.atridad.openclimb.utils.DateFormatUtils import com.atridad.ascently.utils.DateFormatUtils
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Entity(tableName = "gyms") @Entity(tableName = "gyms")

View File

@@ -1,10 +1,10 @@
package com.atridad.openclimb.data.model package com.atridad.ascently.data.model
import androidx.room.Entity import androidx.room.Entity
import androidx.room.ForeignKey import androidx.room.ForeignKey
import androidx.room.Index import androidx.room.Index
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.atridad.openclimb.utils.DateFormatUtils import com.atridad.ascently.utils.DateFormatUtils
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Entity( @Entity(

View File

@@ -1,25 +1,25 @@
package com.atridad.openclimb.data.repository package com.atridad.ascently.data.repository
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import com.atridad.openclimb.data.database.OpenClimbDatabase import com.atridad.ascently.data.database.AscentlyDatabase
import com.atridad.openclimb.data.format.BackupAttempt import com.atridad.ascently.data.format.BackupAttempt
import com.atridad.openclimb.data.format.BackupClimbSession import com.atridad.ascently.data.format.BackupClimbSession
import com.atridad.openclimb.data.format.BackupGym import com.atridad.ascently.data.format.BackupGym
import com.atridad.openclimb.data.format.BackupProblem import com.atridad.ascently.data.format.BackupProblem
import com.atridad.openclimb.data.format.ClimbDataBackup import com.atridad.ascently.data.format.ClimbDataBackup
import com.atridad.openclimb.data.format.DeletedItem import com.atridad.ascently.data.format.DeletedItem
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import com.atridad.openclimb.data.state.DataStateManager import com.atridad.ascently.data.state.DataStateManager
import com.atridad.openclimb.utils.DateFormatUtils import com.atridad.ascently.utils.DateFormatUtils
import com.atridad.openclimb.utils.ZipExportImportUtils import com.atridad.ascently.utils.ZipExportImportUtils
import java.io.File import java.io.File
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.serialization.json.Json 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 gymDao = database.gymDao()
private val problemDao = database.problemDao() private val problemDao = database.problemDao()
private val sessionDao = database.climbSessionDao() private val sessionDao = database.climbSessionDao()
@@ -157,7 +157,7 @@ class ClimbRepository(database: OpenClimbDatabase, private val context: Context)
.filter { imagePath -> .filter { imagePath ->
try { try {
val imageFile = val imageFile =
com.atridad.openclimb.utils.ImageUtils.getImageFile( com.atridad.ascently.utils.ImageUtils.getImageFile(
context, context,
imagePath imagePath
) )

View File

@@ -1,10 +1,10 @@
package com.atridad.openclimb.data.state package com.atridad.ascently.data.state
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log import android.util.Log
import com.atridad.openclimb.utils.DateFormatUtils
import androidx.core.content.edit 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 * 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 { companion object {
private const val TAG = "DataStateManager" 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_LAST_MODIFIED = "last_modified_timestamp"
private const val KEY_INITIALIZED = "state_initialized" private const val KEY_INITIALIZED = "state_initialized"
} }
@@ -58,5 +58,4 @@ class DataStateManager(context: Context) {
private fun markAsInitialized() { private fun markAsInitialized() {
prefs.edit { putBoolean(KEY_INITIALIZED, true) } prefs.edit { putBoolean(KEY_INITIALIZED, true) }
} }
} }

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.data.sync package com.atridad.ascently.data.sync
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
@@ -7,16 +7,16 @@ import android.net.NetworkCapabilities
import android.util.Log import android.util.Log
import androidx.annotation.RequiresPermission import androidx.annotation.RequiresPermission
import androidx.core.content.edit import androidx.core.content.edit
import com.atridad.openclimb.data.format.BackupAttempt import com.atridad.ascently.data.format.BackupAttempt
import com.atridad.openclimb.data.format.BackupClimbSession import com.atridad.ascently.data.format.BackupClimbSession
import com.atridad.openclimb.data.format.BackupGym import com.atridad.ascently.data.format.BackupGym
import com.atridad.openclimb.data.format.BackupProblem import com.atridad.ascently.data.format.BackupProblem
import com.atridad.openclimb.data.format.ClimbDataBackup import com.atridad.ascently.data.format.ClimbDataBackup
import com.atridad.openclimb.data.repository.ClimbRepository import com.atridad.ascently.data.repository.ClimbRepository
import com.atridad.openclimb.data.state.DataStateManager import com.atridad.ascently.data.state.DataStateManager
import com.atridad.openclimb.utils.DateFormatUtils import com.atridad.ascently.utils.DateFormatUtils
import com.atridad.openclimb.utils.ImageNamingUtils import com.atridad.ascently.utils.ImageNamingUtils
import com.atridad.openclimb.utils.ImageUtils import com.atridad.ascently.utils.ImageUtils
import java.io.IOException import java.io.IOException
import java.io.Serializable import java.io.Serializable
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit

View File

@@ -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.Icons
import androidx.compose.material.icons.filled.* import androidx.compose.material.icons.filled.*

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.navigation package com.atridad.ascently.navigation
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.service package com.atridad.ascently.service
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
@@ -8,10 +8,10 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.IBinder import android.os.IBinder
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.atridad.openclimb.MainActivity import com.atridad.ascently.MainActivity
import com.atridad.openclimb.R import com.atridad.ascently.R
import com.atridad.openclimb.data.database.OpenClimbDatabase import com.atridad.ascently.data.database.AscentlyDatabase
import com.atridad.openclimb.data.repository.ClimbRepository import com.atridad.ascently.data.repository.ClimbRepository
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.firstOrNull
import java.time.LocalDateTime import java.time.LocalDateTime
@@ -52,7 +52,7 @@ class SessionTrackingService : Service() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
val database = OpenClimbDatabase.getDatabase(this) val database = AscentlyDatabase.getDatabase(this)
repository = ClimbRepository(database, this) repository = ClimbRepository(database, this)
notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
@@ -75,8 +75,8 @@ class SessionTrackingService : Service() {
sessionId != null -> repository.getSessionById(sessionId) sessionId != null -> repository.getSessionById(sessionId)
else -> repository.getActiveSession() else -> repository.getActiveSession()
} }
if (targetSession != null && targetSession.status == com.atridad.openclimb.data.model.SessionStatus.ACTIVE) { if (targetSession != null && targetSession.status == com.atridad.ascently.data.model.SessionStatus.ACTIVE) {
val completed = with(com.atridad.openclimb.data.model.ClimbSession) { targetSession.complete() } val completed = with(com.atridad.ascently.data.model.ClimbSession) { targetSession.complete() }
repository.updateSession(completed) repository.updateSession(completed)
} }
} finally { } finally {
@@ -127,7 +127,7 @@ class SessionTrackingService : Service() {
} }
val session = repository.getSessionById(sessionId) 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() stopSessionTracking()
break break
} }
@@ -175,7 +175,7 @@ class SessionTrackingService : Service() {
val session = runBlocking { val session = runBlocking {
repository.getSessionById(sessionId) 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() stopSessionTracking()
return return
} }

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.ui package com.atridad.ascently.ui
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
@@ -17,21 +17,21 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute import androidx.navigation.toRoute
import com.atridad.openclimb.data.database.OpenClimbDatabase import com.atridad.ascently.data.database.AscentlyDatabase
import com.atridad.openclimb.data.repository.ClimbRepository import com.atridad.ascently.data.repository.ClimbRepository
import com.atridad.openclimb.data.sync.SyncService import com.atridad.ascently.data.sync.SyncService
import com.atridad.openclimb.navigation.Screen import com.atridad.ascently.navigation.Screen
import com.atridad.openclimb.navigation.bottomNavigationItems import com.atridad.ascently.navigation.bottomNavigationItems
import com.atridad.openclimb.ui.components.NotificationPermissionDialog import com.atridad.ascently.ui.components.NotificationPermissionDialog
import com.atridad.openclimb.ui.screens.* import com.atridad.ascently.ui.screens.*
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
import com.atridad.openclimb.ui.viewmodel.ClimbViewModelFactory import com.atridad.ascently.ui.viewmodel.ClimbViewModelFactory
import com.atridad.openclimb.utils.AppShortcutManager import com.atridad.ascently.utils.AppShortcutManager
import com.atridad.openclimb.utils.NotificationPermissionUtils import com.atridad.ascently.utils.NotificationPermissionUtils
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun OpenClimbApp( fun AscentlyApp(
shortcutAction: String? = null, shortcutAction: String? = null,
lastUsedGymId: String? = null, lastUsedGymId: String? = null,
onShortcutActionProcessed: () -> Unit = {} onShortcutActionProcessed: () -> Unit = {}
@@ -39,9 +39,9 @@ fun OpenClimbApp(
val navController = rememberNavController() val navController = rememberNavController()
val context = LocalContext.current val context = LocalContext.current
var lastUsedGym by remember { mutableStateOf<com.atridad.openclimb.data.model.Gym?>(null) } var lastUsedGym by remember { mutableStateOf<com.atridad.ascently.data.model.Gym?>(null) }
val database = remember { OpenClimbDatabase.getDatabase(context) } val database = remember { AscentlyDatabase.getDatabase(context) }
val repository = remember { ClimbRepository(database, context) } val repository = remember { ClimbRepository(database, context) }
val syncService = remember { SyncService(context, repository) } val syncService = remember { SyncService(context, repository) }
val viewModel: ClimbViewModel = val viewModel: ClimbViewModel =
@@ -115,7 +115,7 @@ fun OpenClimbApp(
LaunchedEffect(shortcutAction, activeSession, gyms, lastUsedGym) { LaunchedEffect(shortcutAction, activeSession, gyms, lastUsedGym) {
if (shortcutAction == AppShortcutManager.ACTION_START_SESSION && gyms.isNotEmpty()) { if (shortcutAction == AppShortcutManager.ACTION_START_SESSION && gyms.isNotEmpty()) {
android.util.Log.d( android.util.Log.d(
"OpenClimbApp", "AscentlyApp",
"Processing shortcut action: activeSession=$activeSession, gyms.size=${gyms.size}, lastUsedGymId=$lastUsedGymId, lastUsedGym=${lastUsedGym?.name}" "Processing shortcut action: activeSession=$activeSession, gyms.size=${gyms.size}, lastUsedGymId=$lastUsedGymId, lastUsedGym=${lastUsedGym?.name}"
) )
@@ -125,12 +125,12 @@ fun OpenClimbApp(
context context
) )
) { ) {
android.util.Log.d("OpenClimbApp", "Showing notification permission dialog") android.util.Log.d("AscentlyApp", "Showing notification permission dialog")
showNotificationPermissionDialog = true showNotificationPermissionDialog = true
} else { } else {
if (gyms.size == 1) { if (gyms.size == 1) {
android.util.Log.d( android.util.Log.d(
"OpenClimbApp", "AscentlyApp",
"Starting session with single gym: ${gyms.first().name}" "Starting session with single gym: ${gyms.first().name}"
) )
viewModel.startSession(context, gyms.first().id) viewModel.startSession(context, gyms.first().id)
@@ -141,13 +141,13 @@ fun OpenClimbApp(
if (targetGym != null) { if (targetGym != null) {
android.util.Log.d( android.util.Log.d(
"OpenClimbApp", "AscentlyApp",
"Starting session with target gym: ${targetGym.name}" "Starting session with target gym: ${targetGym.name}"
) )
viewModel.startSession(context, targetGym.id) viewModel.startSession(context, targetGym.id)
} else { } else {
android.util.Log.d( android.util.Log.d(
"OpenClimbApp", "AscentlyApp",
"No target gym found, navigating to selection" "No target gym found, navigating to selection"
) )
navController.navigate(Screen.AddEditSession()) navController.navigate(Screen.AddEditSession())
@@ -156,7 +156,7 @@ fun OpenClimbApp(
} }
} else { } else {
android.util.Log.d( android.util.Log.d(
"OpenClimbApp", "AscentlyApp",
"Active session already exists: ${activeSession?.id}" "Active session already exists: ${activeSession?.id}"
) )
} }
@@ -168,7 +168,7 @@ fun OpenClimbApp(
var fabConfig by remember { mutableStateOf<FabConfig?>(null) } var fabConfig by remember { mutableStateOf<FabConfig?>(null) }
Scaffold( Scaffold(
bottomBar = { OpenClimbBottomNavigation(navController = navController) }, bottomBar = { AscentlyBottomNavigation(navController = navController) },
floatingActionButton = { floatingActionButton = {
fabConfig?.let { config -> fabConfig?.let { config ->
FloatingActionButton( FloatingActionButton(
@@ -363,7 +363,7 @@ fun OpenClimbApp(
} }
@Composable @Composable
fun OpenClimbBottomNavigation(navController: NavHostController) { fun AscentlyBottomNavigation(navController: NavHostController) {
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route val currentRoute = navBackStackEntry?.destination?.route

View File

@@ -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.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@@ -10,9 +10,9 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.data.model.ClimbSession import com.atridad.ascently.data.model.ClimbSession
import com.atridad.openclimb.data.model.Gym import com.atridad.ascently.data.model.Gym
import com.atridad.openclimb.ui.theme.CustomIcons import com.atridad.ascently.ui.theme.CustomIcons
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.temporal.ChronoUnit import java.time.temporal.ChronoUnit

View File

@@ -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.Canvas
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box

View File

@@ -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.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background

View File

@@ -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.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.ui.components package com.atridad.ascently.ui.components
import android.Manifest import android.Manifest
import android.content.pm.PackageManager import android.content.pm.PackageManager
@@ -25,7 +25,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import com.atridad.openclimb.utils.ImageUtils import com.atridad.ascently.utils.ImageUtils
import java.io.File import java.io.File
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*

View File

@@ -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.Canvas
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box

View File

@@ -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") }
}
}
}
}
}

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.ui.components package com.atridad.ascently.ui.components
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Matrix import android.graphics.Matrix
@@ -12,7 +12,7 @@ import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.exifinterface.media.ExifInterface import androidx.exifinterface.media.ExifInterface
import com.atridad.openclimb.utils.ImageUtils import com.atridad.ascently.utils.ImageUtils
import java.io.File import java.io.File
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext

View File

@@ -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.AnimatedVisibility
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.ui.health package com.atridad.ascently.ui.health
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.compose.foundation.layout.* 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.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.data.health.HealthConnectManager import com.atridad.ascently.data.health.HealthConnectManager
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)

View File

@@ -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.layout.*
import androidx.compose.foundation.lazy.LazyColumn 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.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import com.atridad.openclimb.ui.components.ImagePicker import com.atridad.ascently.ui.components.ImagePicker
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
import java.time.LocalDateTime import java.time.LocalDateTime
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first

View File

@@ -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.layout.*
import androidx.compose.foundation.lazy.LazyColumn 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.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.R import com.atridad.ascently.R
import com.atridad.openclimb.data.model.AttemptResult import com.atridad.ascently.data.model.AttemptResult
import com.atridad.openclimb.data.model.ClimbType import com.atridad.ascently.data.model.ClimbType
import com.atridad.openclimb.data.model.DifficultySystem import com.atridad.ascently.data.model.DifficultySystem
import com.atridad.openclimb.ui.components.BarChart import com.atridad.ascently.ui.components.BarChart
import com.atridad.openclimb.ui.components.BarChartDataPoint import com.atridad.ascently.ui.components.BarChartDataPoint
import com.atridad.openclimb.ui.components.SyncIndicator import com.atridad.ascently.ui.components.SyncIndicator
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -39,7 +39,7 @@ fun AnalyticsScreen(viewModel: ClimbViewModel) {
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_mountains), painter = painterResource(id = R.drawable.ic_mountains),
contentDescription = "OpenClimb Logo", contentDescription = "Ascently Logo",
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )
@@ -200,7 +200,9 @@ fun GradeDistributionChartCard(gradeDistributionData: List<GradeDistributionData
}, },
modifier = modifier =
Modifier.menuAnchor( Modifier.menuAnchor(
type = ExposedDropdownMenuAnchorType.PrimaryNotEditable, type =
ExposedDropdownMenuAnchorType
.PrimaryNotEditable,
enabled = true enabled = true
) )
.width(120.dp), .width(120.dp),
@@ -394,9 +396,9 @@ data class GradeDistributionDataPoint(
) )
fun calculateGradeDistribution( fun calculateGradeDistribution(
sessions: List<com.atridad.openclimb.data.model.ClimbSession>, sessions: List<com.atridad.ascently.data.model.ClimbSession>,
problems: List<com.atridad.openclimb.data.model.Problem>, problems: List<com.atridad.ascently.data.model.Problem>,
attempts: List<com.atridad.openclimb.data.model.Attempt> attempts: List<com.atridad.ascently.data.model.Attempt>
): List<GradeDistributionDataPoint> { ): List<GradeDistributionDataPoint> {
if (sessions.isEmpty() || problems.isEmpty() || attempts.isEmpty()) { if (sessions.isEmpty() || problems.isEmpty() || attempts.isEmpty()) {
return emptyList() return emptyList()

View File

@@ -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.BorderStroke
import androidx.compose.foundation.clickable 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.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import com.atridad.openclimb.ui.components.FullscreenImageViewer import com.atridad.ascently.ui.components.FullscreenImageViewer
import com.atridad.openclimb.ui.components.ImageDisplaySection import com.atridad.ascently.ui.components.ImageDisplaySection
import com.atridad.openclimb.ui.theme.CustomIcons import com.atridad.ascently.ui.theme.CustomIcons
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first

View File

@@ -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.layout.*
import androidx.compose.foundation.lazy.LazyColumn 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.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.R import com.atridad.ascently.R
import com.atridad.openclimb.data.model.Gym import com.atridad.ascently.data.model.Gym
import com.atridad.openclimb.ui.components.SyncIndicator import com.atridad.ascently.ui.components.SyncIndicator
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -28,7 +28,7 @@ fun GymsScreen(viewModel: ClimbViewModel, onNavigateToGymDetail: (String) -> Uni
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_mountains), painter = painterResource(id = R.drawable.ic_mountains),
contentDescription = "OpenClimb Logo", contentDescription = "Ascently Logo",
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )

View File

@@ -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.layout.*
import androidx.compose.foundation.lazy.LazyColumn 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.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.R import com.atridad.ascently.R
import com.atridad.openclimb.data.model.Attempt import com.atridad.ascently.data.model.Attempt
import com.atridad.openclimb.data.model.AttemptResult import com.atridad.ascently.data.model.AttemptResult
import com.atridad.openclimb.data.model.ClimbType import com.atridad.ascently.data.model.ClimbType
import com.atridad.openclimb.data.model.Gym import com.atridad.ascently.data.model.Gym
import com.atridad.openclimb.data.model.Problem import com.atridad.ascently.data.model.Problem
import com.atridad.openclimb.ui.components.SyncIndicator import com.atridad.ascently.ui.components.SyncIndicator
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@@ -57,7 +57,7 @@ fun ProblemsScreen(viewModel: ClimbViewModel, onNavigateToProblemDetail: (String
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_mountains), painter = painterResource(id = R.drawable.ic_mountains),
contentDescription = "OpenClimb Logo", contentDescription = "Ascently Logo",
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )

View File

@@ -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.layout.*
import androidx.compose.foundation.lazy.LazyColumn 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.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.R import com.atridad.ascently.R
import com.atridad.openclimb.data.model.ClimbSession import com.atridad.ascently.data.model.ClimbSession
import com.atridad.openclimb.data.model.SessionStatus import com.atridad.ascently.data.model.SessionStatus
import com.atridad.openclimb.ui.components.ActiveSessionBanner import com.atridad.ascently.ui.components.ActiveSessionBanner
import com.atridad.openclimb.ui.components.SyncIndicator import com.atridad.ascently.ui.components.SyncIndicator
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
@@ -46,7 +46,7 @@ fun SessionsScreen(viewModel: ClimbViewModel, onNavigateToSessionDetail: (String
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_mountains), painter = painterResource(id = R.drawable.ic_mountains),
contentDescription = "OpenClimb Logo", contentDescription = "Ascently Logo",
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.ui.screens package com.atridad.ascently.ui.screens
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts 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.res.painterResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.atridad.openclimb.R import com.atridad.ascently.R
import com.atridad.openclimb.ui.components.SyncIndicator import com.atridad.ascently.ui.components.SyncIndicator
import com.atridad.openclimb.ui.health.HealthConnectCard import com.atridad.ascently.ui.health.HealthConnectCard
import com.atridad.openclimb.ui.viewmodel.ClimbViewModel import com.atridad.ascently.ui.viewmodel.ClimbViewModel
import java.io.File import java.io.File
import java.time.Instant import java.time.Instant
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -86,7 +86,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) {
// Only allow ZIP files // Only allow ZIP files
if (!fileName.lowercase().endsWith(".zip")) { if (!fileName.lowercase().endsWith(".zip")) {
viewModel.setError( 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 return@let
} }
@@ -129,7 +129,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) {
) { ) {
Icon( Icon(
painter = painterResource(id = R.drawable.ic_mountains), painter = painterResource(id = R.drawable.ic_mountains),
contentDescription = "OpenClimb Logo", contentDescription = "Ascently Logo",
modifier = Modifier.size(32.dp), modifier = Modifier.size(32.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )
@@ -336,7 +336,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) {
ListItem( ListItem(
headlineContent = { Text("Setup Sync") }, headlineContent = { Text("Setup Sync") },
supportingContent = { supportingContent = {
Text("Connect to your OpenClimb sync server") Text("Connect to your Ascently sync server")
}, },
leadingContent = { leadingContent = {
Icon(Icons.Default.CloudSync, contentDescription = null) Icon(Icons.Default.CloudSync, contentDescription = null)
@@ -421,7 +421,7 @@ fun SettingsScreen(viewModel: ClimbViewModel) {
TextButton( TextButton(
onClick = { onClick = {
val defaultFileName = val defaultFileName =
"openclimb_export_${ "ascently_export_${
java.time.LocalDateTime.now() java.time.LocalDateTime.now()
.toString() .toString()
.replace(":", "-") .replace(":", "-")
@@ -604,11 +604,11 @@ fun SettingsScreen(viewModel: ClimbViewModel) {
painterResource( painterResource(
id = R.drawable.ic_mountains id = R.drawable.ic_mountains
), ),
contentDescription = "OpenClimb Logo", contentDescription = "Ascently Logo",
modifier = Modifier.size(24.dp), modifier = Modifier.size(24.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )
Text("OpenClimb") Text("Ascently")
} }
}, },
supportingContent = { Text("Track your climbing progress") }, supportingContent = { Text("Track your climbing progress") },

View File

@@ -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.Color

View File

@@ -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.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.ui.theme package com.atridad.ascently.ui.theme
import android.app.Activity import android.app.Activity
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
@@ -88,7 +88,7 @@ private val LightColorScheme = lightColorScheme(
) )
@Composable @Composable
fun OpenClimbTheme( fun AscentlyTheme(
darkTheme: Boolean = isSystemInDarkTheme(), darkTheme: Boolean = isSystemInDarkTheme(),
// Dynamic color is available on Android 12+ and provides full Material You theming // Dynamic color is available on Android 12+ and provides full Material You theming
// When enabled, it adapts to the user's system wallpaper colors // When enabled, it adapts to the user's system wallpaper colors

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.ui.theme package com.atridad.ascently.ui.theme
import androidx.compose.material3.Typography import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle

View File

@@ -1,17 +1,17 @@
package com.atridad.openclimb.ui.viewmodel package com.atridad.ascently.ui.viewmodel
import android.content.Context import android.content.Context
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.atridad.openclimb.data.health.HealthConnectManager import com.atridad.ascently.data.health.HealthConnectManager
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import com.atridad.openclimb.data.repository.ClimbRepository import com.atridad.ascently.data.repository.ClimbRepository
import com.atridad.openclimb.data.sync.SyncService import com.atridad.ascently.data.sync.SyncService
import com.atridad.openclimb.service.SessionTrackingService import com.atridad.ascently.service.SessionTrackingService
import com.atridad.openclimb.utils.ImageNamingUtils import com.atridad.ascently.utils.ImageNamingUtils
import com.atridad.openclimb.utils.ImageUtils import com.atridad.ascently.utils.ImageUtils
import com.atridad.openclimb.utils.SessionShareUtils import com.atridad.ascently.utils.SessionShareUtils
import com.atridad.openclimb.widget.ClimbStatsWidgetProvider import com.atridad.ascently.widget.ClimbStatsWidgetProvider
import java.io.File import java.io.File
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.* import kotlinx.coroutines.flow.*
@@ -260,7 +260,7 @@ class ClimbViewModel(
viewModelScope.launch { viewModelScope.launch {
android.util.Log.d("ClimbViewModel", "startSession called with gymId: $gymId") android.util.Log.d("ClimbViewModel", "startSession called with gymId: $gymId")
if (!com.atridad.openclimb.utils.NotificationPermissionUtils if (!com.atridad.ascently.utils.NotificationPermissionUtils
.isNotificationPermissionGranted(context) .isNotificationPermissionGranted(context)
) { ) {
android.util.Log.d("ClimbViewModel", "Notification permission not granted") android.util.Log.d("ClimbViewModel", "Notification permission not granted")
@@ -305,7 +305,7 @@ class ClimbViewModel(
fun endSession(context: Context, sessionId: String) { fun endSession(context: Context, sessionId: String) {
viewModelScope.launch { viewModelScope.launch {
if (!com.atridad.openclimb.utils.NotificationPermissionUtils if (!com.atridad.ascently.utils.NotificationPermissionUtils
.isNotificationPermissionGranted(context) .isNotificationPermissionGranted(context)
) { ) {
_uiState.value = _uiState.value =
@@ -416,7 +416,7 @@ class ClimbViewModel(
if (!file.name.lowercase().endsWith(".zip")) { if (!file.name.lowercase().endsWith(".zip")) {
throw Exception( 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."
) )
} }

View File

@@ -1,10 +1,10 @@
package com.atridad.openclimb.ui.viewmodel package com.atridad.ascently.ui.viewmodel
import android.content.Context import android.content.Context
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.atridad.openclimb.data.repository.ClimbRepository import com.atridad.ascently.data.repository.ClimbRepository
import com.atridad.openclimb.data.sync.SyncService import com.atridad.ascently.data.sync.SyncService
class ClimbViewModelFactory( class ClimbViewModelFactory(
private val repository: ClimbRepository, private val repository: ClimbRepository,

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.utils package com.atridad.ascently.utils
import java.time.Instant import java.time.Instant
import java.time.ZoneOffset import java.time.ZoneOffset

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.utils package com.atridad.ascently.utils
import java.security.MessageDigest import java.security.MessageDigest
import java.util.* import java.util.*

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.utils package com.atridad.ascently.utils
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context

View File

@@ -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<String>)
}
}
}
}
// 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<Pair<String, String>>()
// 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<String>)
}
}
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")
}
}

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.utils package com.atridad.ascently.utils
import android.Manifest import android.Manifest
import android.content.Context import android.content.Context

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.utils package com.atridad.ascently.utils
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -7,7 +7,7 @@ import android.graphics.drawable.GradientDrawable
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.graphics.createBitmap import androidx.core.graphics.createBitmap
import androidx.core.graphics.toColorInt import androidx.core.graphics.toColorInt
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.time.LocalDateTime import java.time.LocalDateTime
@@ -382,7 +382,7 @@ object SessionShareUtils {
isAntiAlias = true isAntiAlias = true
textAlign = Paint.Align.CENTER textAlign = Paint.Align.CENTER
} }
canvas.drawText("OpenClimb", width / 2f, height - 40f, brandingPaint) canvas.drawText("Ascently", width / 2f, height - 40f, brandingPaint)
// Save to file // Save to file
val shareDir = File(context.cacheDir, "shares") val shareDir = File(context.cacheDir, "shares")
@@ -481,7 +481,7 @@ object SessionShareUtils {
action = Intent.ACTION_SEND action = Intent.ACTION_SEND
type = "image/png" type = "image/png"
putExtra(Intent.EXTRA_STREAM, uri) 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) addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
} }

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.utils package com.atridad.ascently.utils
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -7,23 +7,23 @@ import android.content.pm.ShortcutManager
import android.graphics.drawable.Icon import android.graphics.drawable.Icon
import android.os.Build import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import com.atridad.openclimb.MainActivity import com.atridad.ascently.MainActivity
import com.atridad.openclimb.R import com.atridad.ascently.R
object AppShortcutManager { object AppShortcutManager {
const val SHORTCUT_START_SESSION = "start_session" const val SHORTCUT_START_SESSION = "start_session"
const val SHORTCUT_END_SESSION = "end_session" const val SHORTCUT_END_SESSION = "end_session"
const val ACTION_START_SESSION = "com.atridad.openclimb.action.START_SESSION" const val ACTION_START_SESSION = "com.atridad.ascently.action.START_SESSION"
const val ACTION_END_SESSION = "com.atridad.openclimb.action.END_SESSION" const val ACTION_END_SESSION = "com.atridad.ascently.action.END_SESSION"
/** Updates the app shortcuts based on current session state */ /** Updates the app shortcuts based on current session state */
fun updateShortcuts( fun updateShortcuts(
context: Context, context: Context,
hasActiveSession: Boolean, hasActiveSession: Boolean,
hasGyms: 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) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
val shortcutManager = context.getSystemService(ShortcutManager::class.java) val shortcutManager = context.getSystemService(ShortcutManager::class.java)
@@ -45,7 +45,7 @@ object AppShortcutManager {
@RequiresApi(Build.VERSION_CODES.N_MR1) @RequiresApi(Build.VERSION_CODES.N_MR1)
private fun createStartSessionShortcut( private fun createStartSessionShortcut(
context: Context, context: Context,
lastUsedGym: com.atridad.openclimb.data.model.Gym? = null lastUsedGym: com.atridad.ascently.data.model.Gym? = null
): ShortcutInfo { ): ShortcutInfo {
val startIntent = val startIntent =
Intent(context, MainActivity::class.java).apply { Intent(context, MainActivity::class.java).apply {

View File

@@ -1,8 +1,8 @@
package com.atridad.openclimb.utils package com.atridad.ascently.utils
import android.content.Context import android.content.Context
import com.atridad.openclimb.data.format.BackupProblem import com.atridad.ascently.data.format.BackupProblem
import com.atridad.openclimb.data.format.ClimbDataBackup import com.atridad.ascently.data.format.ClimbDataBackup
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
@@ -33,14 +33,14 @@ object ZipExportImportUtils {
context.getExternalFilesDir( context.getExternalFilesDir(
android.os.Environment.DIRECTORY_DOCUMENTS android.os.Environment.DIRECTORY_DOCUMENTS
), ),
"OpenClimb" "Ascently"
) )
if (!exportDir.exists()) { if (!exportDir.exists()) {
exportDir.mkdirs() exportDir.mkdirs()
} }
val timestamp = LocalDateTime.now().toString().replace(":", "-").replace(".", "-") val timestamp = LocalDateTime.now().toString().replace(":", "-").replace(".", "-")
val zipFile = File(exportDir, "openclimb_export_$timestamp.zip") val zipFile = File(exportDir, "ascently_export_$timestamp.zip")
try { try {
ZipOutputStream(FileOutputStream(zipFile)).use { zipOut -> ZipOutputStream(FileOutputStream(zipFile)).use { zipOut ->
@@ -182,8 +182,8 @@ object ZipExportImportUtils {
referencedImagePaths: Set<String> referencedImagePaths: Set<String>
): String { ): String {
return buildString { return buildString {
appendLine("OpenClimb Export Metadata") appendLine("Ascently Export Metadata")
appendLine("=======================") appendLine("========================")
appendLine("Export Date: ${exportData.exportedAt}") appendLine("Export Date: ${exportData.exportedAt}")
appendLine("Version: ${exportData.version}") appendLine("Version: ${exportData.version}")
appendLine("Gyms: ${exportData.gyms.size}") appendLine("Gyms: ${exportData.gyms.size}")

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb.widget package com.atridad.ascently.widget
import android.app.PendingIntent import android.app.PendingIntent
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
@@ -7,10 +7,10 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.widget.RemoteViews import android.widget.RemoteViews
import com.atridad.openclimb.MainActivity import com.atridad.ascently.MainActivity
import com.atridad.openclimb.R import com.atridad.ascently.R
import com.atridad.openclimb.data.database.OpenClimbDatabase import com.atridad.ascently.data.database.AscentlyDatabase
import com.atridad.openclimb.data.repository.ClimbRepository import com.atridad.ascently.data.repository.ClimbRepository
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
@@ -45,7 +45,7 @@ class ClimbStatsWidgetProvider : AppWidgetProvider() {
) { ) {
coroutineScope.launch { coroutineScope.launch {
try { try {
val database = OpenClimbDatabase.getDatabase(context) val database = AscentlyDatabase.getDatabase(context)
val repository = ClimbRepository(database, context) val repository = ClimbRepository(database, context)
// Fetch stats data // Fetch stats data
@@ -65,10 +65,10 @@ class ClimbStatsWidgetProvider : AppWidgetProvider() {
attempts.any { attempt -> attempts.any { attempt ->
attempt.problemId == problem.id && attempt.problemId == problem.id &&
(attempt.result == (attempt.result ==
com.atridad.openclimb.data.model com.atridad.ascently.data.model
.AttemptResult.SUCCESS || .AttemptResult.SUCCESS ||
attempt.result == attempt.result ==
com.atridad.openclimb.data.model com.atridad.ascently.data.model
.AttemptResult.FLASH) .AttemptResult.FLASH)
} }
} }

View File

@@ -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")
}
}
}
}
}
}

View File

@@ -26,7 +26,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="OpenClimb" android:text="Ascently"
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" android:textStyle="bold"
android:textColor="@color/widget_text_primary" /> android:textColor="@color/widget_text_primary" />

View File

@@ -1,5 +1,5 @@
<resources> <resources>
<string name="app_name">OpenClimb</string> <string name="app_name">Ascently</string>
<string name="session_tracking_service_description">Tracks active climbing sessions and displays session information in the notification area</string> <string name="session_tracking_service_description">Tracks active climbing sessions and displays session information in the notification area</string>
<!-- App Shortcuts --> <!-- App Shortcuts -->

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<style name="Theme.OpenClimb" parent="android:Theme.Material.Light.NoActionBar" /> <style name="Theme.Ascently" parent="android:Theme.Material.Light.NoActionBar" />
<style name="Theme.OpenClimb.Splash" parent="Theme.OpenClimb"> <style name="Theme.Ascently.Splash" parent="Theme.Ascently">
<item name="android:windowSplashScreenBackground">@color/splash_background</item> <item name="android:windowSplashScreenBackground">@color/splash_background</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_mountains</item> <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_mountains</item>
<item name="android:windowSplashScreenAnimationDuration">200</item> <item name="android:windowSplashScreenAnimationDuration">200</item>
</style> </style>
</resources> </resources>

View File

@@ -1,7 +1,7 @@
package com.atridad.openclimb package com.atridad.ascently
import com.atridad.openclimb.data.format.* import com.atridad.ascently.data.format.*
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import org.junit.Assert.* import org.junit.Assert.*

View File

@@ -1,7 +1,7 @@
package com.atridad.openclimb package com.atridad.ascently
import com.atridad.openclimb.data.format.* import com.atridad.ascently.data.format.*
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import java.time.Instant import java.time.Instant
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import org.junit.Assert.* import org.junit.Assert.*

View File

@@ -1,7 +1,7 @@
package com.atridad.openclimb package com.atridad.ascently
import com.atridad.openclimb.data.format.* import com.atridad.ascently.data.format.*
import com.atridad.openclimb.data.model.* import com.atridad.ascently.data.model.*
import org.junit.Assert.* import org.junit.Assert.*
import org.junit.Test import org.junit.Test

View File

@@ -1,4 +1,4 @@
package com.atridad.openclimb package com.atridad.ascently
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter

View File

@@ -11,6 +11,7 @@ pluginManagement {
gradlePluginPortal() gradlePluginPortal()
} }
} }
dependencyResolutionManagement { dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories { repositories {
@@ -20,5 +21,6 @@ dependencyResolutionManagement {
} }
} }
rootProject.name = "OpenClimb" rootProject.name = "Ascently"
include(":app") include(":app")

View File

@@ -20,7 +20,7 @@
containerPortal = D24C19602E75002A0045894C /* Project object */; containerPortal = D24C19602E75002A0045894C /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = D24C19672E75002A0045894C; remoteGlobalIDString = D24C19672E75002A0045894C;
remoteInfo = OpenClimb; remoteInfo = Ascently;
}; };
D2FE949E2E78FEE1008CDB25 /* PBXContainerItemProxy */ = { D2FE949E2E78FEE1008CDB25 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
@@ -46,9 +46,9 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference 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 = "<group>"; }; D268B79E2E83894A003AA641 /* SessionStatusLiveExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionStatusLiveExtension.entitlements; sourceTree = "<group>"; };
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; }; 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; }; 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; }; 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 */ /* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
D28C3C8B2E75111D00F7AEE9 /* Exceptions for "OpenClimb" folder in "OpenClimb" target */ = { D28C3C8B2E75111D00F7AEE9 /* Exceptions for "Ascently" folder in "Ascently" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet; isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = ( membershipExceptions = (
Info.plist, Info.plist,
); );
target = D24C19672E75002A0045894C /* OpenClimb */; target = D24C19672E75002A0045894C /* Ascently */;
}; };
D2FE94A42E78FEE1008CDB25 /* Exceptions for "SessionStatusLive" folder in "SessionStatusLiveExtension" target */ = { D2FE94A42E78FEE1008CDB25 /* Exceptions for "SessionStatusLive" folder in "SessionStatusLiveExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet; isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
@@ -73,17 +73,17 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFileSystemSynchronizedRootGroup section */
D24C196A2E75002A0045894C /* OpenClimb */ = { D24C196A2E75002A0045894C /* Ascently */ = {
isa = PBXFileSystemSynchronizedRootGroup; isa = PBXFileSystemSynchronizedRootGroup;
exceptions = ( exceptions = (
D28C3C8B2E75111D00F7AEE9 /* Exceptions for "OpenClimb" folder in "OpenClimb" target */, D28C3C8B2E75111D00F7AEE9 /* Exceptions for "Ascently" folder in "Ascently" target */,
); );
path = OpenClimb; path = Ascently;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D2F32FAE2E90B26500B1BC56 /* OpenClimbTests */ = { D2F32FAE2E90B26500B1BC56 /* AscentlyTests */ = {
isa = PBXFileSystemSynchronizedRootGroup; isa = PBXFileSystemSynchronizedRootGroup;
path = OpenClimbTests; path = AscentlyTests;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D2FE94902E78FEE0008CDB25 /* SessionStatusLive */ = { D2FE94902E78FEE0008CDB25 /* SessionStatusLive */ = {
@@ -129,9 +129,9 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D268B79E2E83894A003AA641 /* SessionStatusLiveExtension.entitlements */, D268B79E2E83894A003AA641 /* SessionStatusLiveExtension.entitlements */,
D24C196A2E75002A0045894C /* OpenClimb */, D24C196A2E75002A0045894C /* Ascently */,
D2FE94902E78FEE0008CDB25 /* SessionStatusLive */, D2FE94902E78FEE0008CDB25 /* SessionStatusLive */,
D2F32FAE2E90B26500B1BC56 /* OpenClimbTests */, D2F32FAE2E90B26500B1BC56 /* AscentlyTests */,
D2FE947F2E78E958008CDB25 /* Frameworks */, D2FE947F2E78E958008CDB25 /* Frameworks */,
D24C19692E75002A0045894C /* Products */, D24C19692E75002A0045894C /* Products */,
); );
@@ -140,9 +140,9 @@
D24C19692E75002A0045894C /* Products */ = { D24C19692E75002A0045894C /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D24C19682E75002A0045894C /* OpenClimb.app */, D24C19682E75002A0045894C /* Ascently.app */,
D2FE948B2E78FEE0008CDB25 /* SessionStatusLiveExtension.appex */, D2FE948B2E78FEE0008CDB25 /* SessionStatusLiveExtension.appex */,
D2F32FAD2E90B26500B1BC56 /* OpenClimbTests.xctest */, D2F32FAD2E90B26500B1BC56 /* AscentlyTests.xctest */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -160,9 +160,9 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
D24C19672E75002A0045894C /* OpenClimb */ = { D24C19672E75002A0045894C /* Ascently */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "OpenClimb" */; buildConfigurationList = D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "Ascently" */;
buildPhases = ( buildPhases = (
D24C19642E75002A0045894C /* Sources */, D24C19642E75002A0045894C /* Sources */,
D24C19652E75002A0045894C /* Frameworks */, D24C19652E75002A0045894C /* Frameworks */,
@@ -175,18 +175,18 @@
D2FE949F2E78FEE1008CDB25 /* PBXTargetDependency */, D2FE949F2E78FEE1008CDB25 /* PBXTargetDependency */,
); );
fileSystemSynchronizedGroups = ( fileSystemSynchronizedGroups = (
D24C196A2E75002A0045894C /* OpenClimb */, D24C196A2E75002A0045894C /* Ascently */,
); );
name = OpenClimb; name = Ascently;
packageProductDependencies = ( packageProductDependencies = (
); );
productName = OpenClimb; productName = Ascently;
productReference = D24C19682E75002A0045894C /* OpenClimb.app */; productReference = D24C19682E75002A0045894C /* Ascently.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
D2F32FAC2E90B26500B1BC56 /* OpenClimbTests */ = { D2F32FAC2E90B26500B1BC56 /* AscentlyTests */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "OpenClimbTests" */; buildConfigurationList = D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "AscentlyTests" */;
buildPhases = ( buildPhases = (
D2F32FA92E90B26500B1BC56 /* Sources */, D2F32FA92E90B26500B1BC56 /* Sources */,
D2F32FAA2E90B26500B1BC56 /* Frameworks */, D2F32FAA2E90B26500B1BC56 /* Frameworks */,
@@ -198,13 +198,13 @@
D2F32FB22E90B26500B1BC56 /* PBXTargetDependency */, D2F32FB22E90B26500B1BC56 /* PBXTargetDependency */,
); );
fileSystemSynchronizedGroups = ( fileSystemSynchronizedGroups = (
D2F32FAE2E90B26500B1BC56 /* OpenClimbTests */, D2F32FAE2E90B26500B1BC56 /* AscentlyTests */,
); );
name = OpenClimbTests; name = AscentlyTests;
packageProductDependencies = ( packageProductDependencies = (
); );
productName = OpenClimbTests; productName = AscentlyTests;
productReference = D2F32FAD2E90B26500B1BC56 /* OpenClimbTests.xctest */; productReference = D2F32FAD2E90B26500B1BC56 /* AscentlyTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test"; productType = "com.apple.product-type.bundle.unit-test";
}; };
D2FE948A2E78FEE0008CDB25 /* SessionStatusLiveExtension */ = { D2FE948A2E78FEE0008CDB25 /* SessionStatusLiveExtension */ = {
@@ -251,7 +251,7 @@
}; };
}; };
}; };
buildConfigurationList = D24C19632E75002A0045894C /* Build configuration list for PBXProject "OpenClimb" */; buildConfigurationList = D24C19632E75002A0045894C /* Build configuration list for PBXProject "Ascently" */;
developmentRegion = en; developmentRegion = en;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
@@ -265,9 +265,9 @@
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
D24C19672E75002A0045894C /* OpenClimb */, D24C19672E75002A0045894C /* Ascently */,
D2FE948A2E78FEE0008CDB25 /* SessionStatusLiveExtension */, D2FE948A2E78FEE0008CDB25 /* SessionStatusLiveExtension */,
D2F32FAC2E90B26500B1BC56 /* OpenClimbTests */, D2F32FAC2E90B26500B1BC56 /* AscentlyTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@@ -323,7 +323,7 @@
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
D2F32FB22E90B26500B1BC56 /* PBXTargetDependency */ = { D2F32FB22E90B26500B1BC56 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = D24C19672E75002A0045894C /* OpenClimb */; target = D24C19672E75002A0045894C /* Ascently */;
targetProxy = D2F32FB12E90B26500B1BC56 /* PBXContainerItemProxy */; targetProxy = D2F32FB12E90B26500B1BC56 /* PBXContainerItemProxy */;
}; };
D2FE949F2E78FEE1008CDB25 /* PBXTargetDependency */ = { D2FE949F2E78FEE1008CDB25 /* PBXTargetDependency */ = {
@@ -462,20 +462,20 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 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_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 25; CURRENT_PROJECT_VERSION = 26;
DEVELOPMENT_TEAM = 4BC9Y2LL4B; DEVELOPMENT_TEAM = 4BC9Y2LL4B;
DRIVERKIT_DEPLOYMENT_TARGET = 24.6; DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = OpenClimb/Info.plist; INFOPLIST_FILE = Ascently/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = OpenClimb; INFOPLIST_KEY_CFBundleDisplayName = Ascently;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports";
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
INFOPLIST_KEY_NSCameraUsageDescription = "OpenClimb needs camera access to take photos of climbing problems."; INFOPLIST_KEY_NSCameraUsageDescription = "Ascently 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_NSPhotoLibraryUsageDescription = "Ascently needs access to your photo library to save and display climbing problem images.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -487,8 +487,8 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.6; MACOSX_DEPLOYMENT_TARGET = 15.6;
MARKETING_VERSION = 1.4.0; MARKETING_VERSION = 2.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -510,20 +510,20 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 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_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 25; CURRENT_PROJECT_VERSION = 26;
DEVELOPMENT_TEAM = 4BC9Y2LL4B; DEVELOPMENT_TEAM = 4BC9Y2LL4B;
DRIVERKIT_DEPLOYMENT_TARGET = 24.6; DRIVERKIT_DEPLOYMENT_TARGET = 24.6;
ENABLE_PREVIEWS = YES; ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = OpenClimb/Info.plist; INFOPLIST_FILE = Ascently/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = OpenClimb; INFOPLIST_KEY_CFBundleDisplayName = Ascently;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.sports";
INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES; INFOPLIST_KEY_LSSupportsOpeningDocumentsInPlace = YES;
INFOPLIST_KEY_NSCameraUsageDescription = "OpenClimb needs camera access to take photos of climbing problems."; INFOPLIST_KEY_NSCameraUsageDescription = "Ascently 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_NSPhotoLibraryUsageDescription = "Ascently needs access to your photo library to save and display climbing problem images.";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -535,8 +535,8 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.6; MACOSX_DEPLOYMENT_TARGET = 15.6;
MARKETING_VERSION = 1.4.0; MARKETING_VERSION = 2.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -562,7 +562,7 @@
DEVELOPMENT_TEAM = 4BC9Y2LL4B; DEVELOPMENT_TEAM = 4BC9Y2LL4B;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; 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)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO; STRING_CATALOG_GENERATE_SYMBOLS = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
@@ -570,7 +570,7 @@
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; 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; name = Debug;
}; };
@@ -583,7 +583,7 @@
DEVELOPMENT_TEAM = 4BC9Y2LL4B; DEVELOPMENT_TEAM = 4BC9Y2LL4B;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; 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)"; PRODUCT_NAME = "$(TARGET_NAME)";
STRING_CATALOG_GENERATE_SYMBOLS = NO; STRING_CATALOG_GENERATE_SYMBOLS = NO;
SWIFT_APPROACHABLE_CONCURRENCY = YES; SWIFT_APPROACHABLE_CONCURRENCY = YES;
@@ -591,7 +591,7 @@
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2"; 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; name = Release;
}; };
@@ -602,7 +602,7 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements; CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 25; CURRENT_PROJECT_VERSION = 26;
DEVELOPMENT_TEAM = 4BC9Y2LL4B; DEVELOPMENT_TEAM = 4BC9Y2LL4B;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SessionStatusLive/Info.plist; INFOPLIST_FILE = SessionStatusLive/Info.plist;
@@ -613,8 +613,8 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.4.0; MARKETING_VERSION = 2.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb.SessionStatusLive; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -632,7 +632,7 @@
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements; CODE_SIGN_ENTITLEMENTS = SessionStatusLiveExtension.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 25; CURRENT_PROJECT_VERSION = 26;
DEVELOPMENT_TEAM = 4BC9Y2LL4B; DEVELOPMENT_TEAM = 4BC9Y2LL4B;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = SessionStatusLive/Info.plist; INFOPLIST_FILE = SessionStatusLive/Info.plist;
@@ -643,8 +643,8 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 1.4.0; MARKETING_VERSION = 2.0.0;
PRODUCT_BUNDLE_IDENTIFIER = com.atridad.OpenClimb.SessionStatusLive; PRODUCT_BUNDLE_IDENTIFIER = com.atridad.Ascently.SessionStatusLive;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES;
@@ -658,7 +658,7 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
D24C19632E75002A0045894C /* Build configuration list for PBXProject "OpenClimb" */ = { D24C19632E75002A0045894C /* Build configuration list for PBXProject "Ascently" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
D24C19712E75002A0045894C /* Debug */, D24C19712E75002A0045894C /* Debug */,
@@ -667,7 +667,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "OpenClimb" */ = { D24C19732E75002A0045894C /* Build configuration list for PBXNativeTarget "Ascently" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
D24C19742E75002A0045894C /* Debug */, D24C19742E75002A0045894C /* Debug */,
@@ -676,7 +676,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "OpenClimbTests" */ = { D2F32FB52E90B26500B1BC56 /* Build configuration list for PBXNativeTarget "AscentlyTests" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
D2F32FB32E90B26500B1BC56 /* Debug */, D2F32FB32E90B26500B1BC56 /* Debug */,

View File

@@ -15,9 +15,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D24C19672E75002A0045894C" BlueprintIdentifier = "D24C19672E75002A0045894C"
BuildableName = "OpenClimb.app" BuildableName = "Ascently.app"
BlueprintName = "OpenClimb" BlueprintName = "Ascently"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@@ -34,9 +34,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D2F32FAC2E90B26500B1BC56" BlueprintIdentifier = "D2F32FAC2E90B26500B1BC56"
BuildableName = "OpenClimbTests.xctest" BuildableName = "AscentlyTests.xctest"
BlueprintName = "OpenClimbTests" BlueprintName = "AscentlyTests"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
@@ -56,9 +56,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D24C19672E75002A0045894C" BlueprintIdentifier = "D24C19672E75002A0045894C"
BuildableName = "OpenClimb.app" BuildableName = "Ascently.app"
BlueprintName = "OpenClimb" BlueprintName = "Ascently"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</LaunchAction> </LaunchAction>
@@ -73,9 +73,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D24C19672E75002A0045894C" BlueprintIdentifier = "D24C19672E75002A0045894C"
BuildableName = "OpenClimb.app" BuildableName = "Ascently.app"
BlueprintName = "OpenClimb" BlueprintName = "Ascently"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>

View File

@@ -19,7 +19,7 @@
BlueprintIdentifier = "D2FE948A2E78FEE0008CDB25" BlueprintIdentifier = "D2FE948A2E78FEE0008CDB25"
BuildableName = "SessionStatusLiveExtension.appex" BuildableName = "SessionStatusLiveExtension.appex"
BlueprintName = "SessionStatusLiveExtension" BlueprintName = "SessionStatusLiveExtension"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
<BuildActionEntry <BuildActionEntry
@@ -31,9 +31,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D24C19672E75002A0045894C" BlueprintIdentifier = "D24C19672E75002A0045894C"
BuildableName = "OpenClimb.app" BuildableName = "Ascently.app"
BlueprintName = "OpenClimb" BlueprintName = "Ascently"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@@ -51,9 +51,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D2F32FAC2E90B26500B1BC56" BlueprintIdentifier = "D2F32FAC2E90B26500B1BC56"
BuildableName = "OpenClimbTests.xctest" BuildableName = "AscentlyTests.xctest"
BlueprintName = "OpenClimbTests" BlueprintName = "AscentlyTests"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
@@ -75,9 +75,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D24C19672E75002A0045894C" BlueprintIdentifier = "D24C19672E75002A0045894C"
BuildableName = "OpenClimb.app" BuildableName = "Ascently.app"
BlueprintName = "OpenClimb" BlueprintName = "Ascently"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
<EnvironmentVariables> <EnvironmentVariables>
@@ -111,9 +111,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "D24C19672E75002A0045894C" BlueprintIdentifier = "D24C19672E75002A0045894C"
BuildableName = "OpenClimb.app" BuildableName = "Ascently.app"
BlueprintName = "OpenClimb" BlueprintName = "Ascently"
ReferencedContainer = "container:OpenClimb.xcodeproj"> ReferencedContainer = "container:Ascently.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>

View File

@@ -4,7 +4,12 @@
<dict> <dict>
<key>SchemeUserState</key> <key>SchemeUserState</key>
<dict> <dict>
<key>OpenClimb.xcscheme_^#shared#^_</key> <key>AscentlyTests.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>Ascently.xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>1</integer> <integer>1</integer>

View File

@@ -4,7 +4,7 @@
<dict> <dict>
<key>com.apple.security.application-groups</key> <key>com.apple.security.application-groups</key>
<array> <array>
<string>group.com.atridad.OpenClimb</string> <string>group.com.atridad.Ascently</string>
</array> </array>
<key>com.apple.developer.healthkit</key> <key>com.apple.developer.healthkit</key>
<true/> <true/>

View File

@@ -1,8 +1,7 @@
import SwiftUI import SwiftUI
@main @main
struct OpenClimbApp: App { struct AscentlyApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ContentView() ContentView()

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -5,7 +5,7 @@ import Foundation
// MARK: - Backup Format Specification v2.0 // MARK: - Backup Format Specification v2.0
/// Root structure for OpenClimb backup data /// Root structure for Ascently backup data
struct DeletedItem: Codable, Hashable { struct DeletedItem: Codable, Hashable {
let id: String let id: String
let type: String // "gym", "problem", "session", "attempt" let type: String // "gym", "problem", "session", "attempt"

Some files were not shown because too many files have changed in this diff Show More