diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0201041b3..937eb640e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 3.0.5
+
+#### What's Fixed
+- Fixed inconsistent corner radius on widget
+- Fixed crash that would occur due to intelligent sort name functionality
+- Fixed crashing on music loading failures that should route to an error
+screen
+
## 3.0.4
#### What's New
diff --git a/README.md b/README.md
index 373c5680d..ceb879047 100644
--- a/README.md
+++ b/README.md
@@ -2,8 +2,8 @@
Auxio
A simple, rational music player for android.
-
-
+
+
diff --git a/app/build.gradle b/app/build.gradle
index 69e5a79a7..7ae1e5b25 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -20,8 +20,8 @@ android {
defaultConfig {
applicationId namespace
- versionName "3.0.4"
- versionCode 28
+ versionName "3.0.5"
+ versionCode 29
minSdk 21
targetSdk 33
diff --git a/app/src/main/java/org/oxycblt/auxio/music/Music.kt b/app/src/main/java/org/oxycblt/auxio/music/Music.kt
index 6df980346..abeb521ed 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt
@@ -363,13 +363,14 @@ interface Genre : MusicParent {
* @author Alexander Capehart (OxygenCobalt)
*/
class SortName(name: String, musicSettings: MusicSettings) : Comparable {
- private val number: Int?
private val collationKey: CollationKey
val thumbString: String?
init {
var sortName = name
if (musicSettings.intelligentSorting) {
+ sortName = sortName.replace(LEADING_PUNCTUATION_REGEX, "")
+
sortName =
sortName.run {
when {
@@ -380,53 +381,34 @@ class SortName(name: String, musicSettings: MusicSettings) : Comparable number = null
- // Whole title is numeric.
- -1 -> {
- number = sortName.toIntOrNull()
- sortName = ""
- }
- // Part of the title is numeric.
- else -> {
- number = sortName.slice(0 until numericEnd).toIntOrNull()
- sortName = sortName.slice(numericEnd until sortName.length)
- }
- }
- } else {
- number = null
+ // Zero pad all numbers to six digits for better sorting
+ sortName = sortName.replace(CONSECUTIVE_DIGITS_REGEX) { it.value.padStart(6, '0') }
}
collationKey = COLLATOR.getCollationKey(sortName)
// Keep track of a string to use in the thumb view.
+ // Simply show '#' for everything before 'A'
// TODO: This needs to be moved elsewhere.
- thumbString = (number?.toString() ?: collationKey?.run { sourceString.first().uppercase() })
+ thumbString =
+ collationKey?.run {
+ val thumbChar = sourceString.firstOrNull()
+ if (thumbChar?.isLetter() == true) thumbChar.uppercase() else "#"
+ }
}
- override fun toString(): String = number?.toString() ?: collationKey.sourceString
+ override fun toString(): String = collationKey.sourceString
- override fun compareTo(other: SortName) =
- when {
- number != null && other.number != null -> number.compareTo(other.number)
- number != null && other.number == null -> -1 // a < b
- number == null && other.number != null -> 1 // a > b
- else -> collationKey.compareTo(other.collationKey)
- }
+ override fun compareTo(other: SortName) = collationKey.compareTo(other.collationKey)
- override fun equals(other: Any?) =
- other is SortName && number == other.number && collationKey == other.collationKey
+ override fun equals(other: Any?) = other is SortName && collationKey == other.collationKey
- override fun hashCode(): Int {
- var hashCode = collationKey.hashCode()
- if (number != null) hashCode = 31 * hashCode + number
- return hashCode
- }
+ override fun hashCode(): Int = collationKey.hashCode()
private companion object {
val COLLATOR: Collator = Collator.getInstance().apply { strength = Collator.PRIMARY }
+ val LEADING_PUNCTUATION_REGEX = Regex("[\\p{Punct}+]")
+ val CONSECUTIVE_DIGITS_REGEX = Regex("\\d+")
}
}
diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt
index 321724d2c..0a67af75d 100644
--- a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt
+++ b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt
@@ -25,15 +25,10 @@ import android.os.Build
import androidx.core.content.ContextCompat
import java.util.LinkedList
import javax.inject.Inject
-import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.async
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
-import kotlinx.coroutines.yield
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.cache.CacheRepository
@@ -351,14 +346,15 @@ constructor(
// Do the initial query of the cache and media databases in parallel.
logD("Starting queries")
- val mediaStoreQueryJob = scope.async { mediaStoreExtractor.query() }
+ val mediaStoreQueryJob = scope.tryAsync { mediaStoreExtractor.query() }
val cache =
if (withCache) {
cacheRepository.readCache()
} else {
null
}
- val query = mediaStoreQueryJob.await()
+ // TODO: Stupid, actually bubble results properly
+ val query = mediaStoreQueryJob.await().getOrThrow()
// Now start processing the queried song information in parallel. Songs that can't be
// received from the cache are consisted incomplete and pushed to a separate channel
@@ -367,10 +363,10 @@ constructor(
val completeSongs = Channel(Channel.UNLIMITED)
val incompleteSongs = Channel(Channel.UNLIMITED)
val mediaStoreJob =
- scope.async {
+ scope.tryAsync {
mediaStoreExtractor.consume(query, cache, incompleteSongs, completeSongs)
}
- val metadataJob = scope.async { tagExtractor.consume(incompleteSongs, completeSongs) }
+ val metadataJob = scope.tryAsync { tagExtractor.consume(incompleteSongs, completeSongs) }
// Await completed raw songs as they are processed.
val rawSongs = LinkedList()
@@ -379,8 +375,8 @@ constructor(
emitIndexing(Indexer.Indexing.Songs(rawSongs.size, query.projectedTotal))
}
// These should be no-ops
- mediaStoreJob.await()
- metadataJob.await()
+ mediaStoreJob.await().getOrThrow()
+ metadataJob.await().getOrThrow()
if (rawSongs.isEmpty()) {
logE("Music library was empty")
@@ -391,13 +387,25 @@ constructor(
// parallel.
logD("Discovered ${rawSongs.size} songs, starting finalization")
emitIndexing(Indexer.Indexing.Indeterminate)
- val libraryJob = scope.async(Dispatchers.Main) { Library.from(rawSongs, musicSettings) }
+ val libraryJob = scope.tryAsync(Dispatchers.Main) { Library.from(rawSongs, musicSettings) }
if (cache == null || cache.invalidated) {
cacheRepository.writeCache(rawSongs)
}
- return libraryJob.await()
+ return libraryJob.await().getOrThrow()
}
+ private inline fun CoroutineScope.tryAsync(
+ context: CoroutineContext = EmptyCoroutineContext,
+ crossinline block: suspend () -> R
+ ) =
+ async(context) {
+ try {
+ Result.success(block())
+ } catch (e: Exception) {
+ Result.failure(e)
+ }
+ }
+
/**
* Emit a new [Indexer.State.Indexing] state. This can be used to signal the current state of
* the music loading process to external code. Assumes that the callee has already checked if
diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt
index 6069beed8..6c1e9e91b 100644
--- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt
+++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt
@@ -95,9 +95,11 @@ constructor(
return if (cornerRadius > 0) {
// If rounded, reduce the bitmap size further to obtain more pronounced
// rounded corners.
- builder.transformations(
- SquareFrameTransform.INSTANCE,
- RoundedCornersTransformation(cornerRadius.toFloat()))
+ builder
+ .size(getSafeRemoteViewsImageSize(context, 10f))
+ .transformations(
+ SquareFrameTransform.INSTANCE,
+ RoundedCornersTransformation(cornerRadius.toFloat()))
} else {
builder.size(getSafeRemoteViewsImageSize(context))
}
diff --git a/fastlane/metadata/android/en-US/changelogs/29.txt b/fastlane/metadata/android/en-US/changelogs/29.txt
new file mode 100644
index 000000000..0eb6a89b9
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/29.txt
@@ -0,0 +1,3 @@
+Auxio 3.0.0 massively improves the music library experience, with a new advanced music loader, a new unified artist model, and a new selection system that makes enqueueing music much simpler.
+This release fixes critical issues.
+For more information, see https://github.com/OxygenCobalt/Auxio/releases/tag/v3.0.5.
\ No newline at end of file