Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
0f976f685f
|
|||
|
c07186a7df
|
@@ -14,8 +14,8 @@ android {
|
|||||||
applicationId = "com.atridad.openclimb"
|
applicationId = "com.atridad.openclimb"
|
||||||
minSdk = 31
|
minSdk = 31
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 8
|
versionCode = 10
|
||||||
versionName = "0.4.1"
|
versionName = "0.4.3"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -410,33 +410,6 @@ fun SessionDetailScreen(sessionId: String, viewModel: ClimbViewModel, onNavigate
|
|||||||
value = "${((successfulAttempts.size.toDouble() / attempts.size) * 100).toInt()}%"
|
value = "${((successfulAttempts.size.toDouble() / attempts.size) * 100).toInt()}%"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Show average grade if available
|
|
||||||
val attemptedProblems = problems.filter { it.id in uniqueProblems }
|
|
||||||
if (attemptedProblems.isNotEmpty()) {
|
|
||||||
val boulderProblems = attemptedProblems.filter { it.climbType == ClimbType.BOULDER }
|
|
||||||
val ropeProblems = attemptedProblems.filter { it.climbType == ClimbType.ROPE }
|
|
||||||
|
|
||||||
val averageGrade = when {
|
|
||||||
boulderProblems.isNotEmpty() && ropeProblems.isNotEmpty() -> {
|
|
||||||
val boulderAvg = calculateAverageGrade(boulderProblems)
|
|
||||||
val ropeAvg = calculateAverageGrade(ropeProblems)
|
|
||||||
"${boulderAvg ?: "N/A"} / ${ropeAvg ?: "N/A"}"
|
|
||||||
}
|
|
||||||
boulderProblems.isNotEmpty() -> calculateAverageGrade(boulderProblems) ?: "N/A"
|
|
||||||
ropeProblems.isNotEmpty() -> calculateAverageGrade(ropeProblems) ?: "N/A"
|
|
||||||
else -> "N/A"
|
|
||||||
}
|
|
||||||
|
|
||||||
StatItem(
|
|
||||||
label = "Average Grade",
|
|
||||||
value = averageGrade
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
StatItem(
|
|
||||||
label = "Average Grade",
|
|
||||||
value = "N/A"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show grade range if available
|
// Show grade range if available
|
||||||
|
|||||||
@@ -35,40 +35,32 @@ object ImageUtils {
|
|||||||
*/
|
*/
|
||||||
fun saveImageFromUri(context: Context, imageUri: Uri): String? {
|
fun saveImageFromUri(context: Context, imageUri: Uri): String? {
|
||||||
return try {
|
return try {
|
||||||
val inputStream = context.contentResolver.openInputStream(imageUri)
|
// Decode bitmap from a fresh stream to avoid mark/reset dependency
|
||||||
inputStream?.use { input ->
|
val originalBitmap = context.contentResolver.openInputStream(imageUri)?.use { input ->
|
||||||
// Decode with options to get EXIF data
|
BitmapFactory.decodeStream(input)
|
||||||
val options = BitmapFactory.Options().apply {
|
} ?: return null
|
||||||
inJustDecodeBounds = true
|
|
||||||
}
|
val orientedBitmap = correctImageOrientation(context, imageUri, originalBitmap)
|
||||||
input.reset()
|
val compressedBitmap = compressImage(orientedBitmap)
|
||||||
BitmapFactory.decodeStream(input, null, options)
|
|
||||||
|
// Generate unique filename
|
||||||
// Reset stream and decode with proper orientation
|
val filename = "${UUID.randomUUID()}.jpg"
|
||||||
input.reset()
|
val imageFile = File(getImagesDirectory(context), filename)
|
||||||
val originalBitmap = BitmapFactory.decodeStream(input)
|
|
||||||
val orientedBitmap = correctImageOrientation(context, imageUri, originalBitmap)
|
// Save compressed image
|
||||||
val compressedBitmap = compressImage(orientedBitmap)
|
FileOutputStream(imageFile).use { output ->
|
||||||
|
compressedBitmap.compress(Bitmap.CompressFormat.JPEG, IMAGE_QUALITY, output)
|
||||||
// Generate unique filename
|
|
||||||
val filename = "${UUID.randomUUID()}.jpg"
|
|
||||||
val imageFile = File(getImagesDirectory(context), filename)
|
|
||||||
|
|
||||||
// Save compressed image
|
|
||||||
FileOutputStream(imageFile).use { output ->
|
|
||||||
compressedBitmap.compress(Bitmap.CompressFormat.JPEG, IMAGE_QUALITY, output)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up bitmaps
|
|
||||||
originalBitmap.recycle()
|
|
||||||
if (orientedBitmap != originalBitmap) {
|
|
||||||
orientedBitmap.recycle()
|
|
||||||
}
|
|
||||||
compressedBitmap.recycle()
|
|
||||||
|
|
||||||
// Return relative path
|
|
||||||
"$IMAGES_DIR/$filename"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up bitmaps
|
||||||
|
originalBitmap.recycle()
|
||||||
|
if (orientedBitmap != originalBitmap) {
|
||||||
|
orientedBitmap.recycle()
|
||||||
|
}
|
||||||
|
compressedBitmap.recycle()
|
||||||
|
|
||||||
|
// Return relative path
|
||||||
|
"$IMAGES_DIR/$filename"
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
null
|
null
|
||||||
|
|||||||
Reference in New Issue
Block a user