Remove the version-specific display name hacks added previously.
Turns out RELATIVE_PATH only includes the directory structure. Oh.
Since this invalidates the purpose of version-specific display name
hacks, we just remove it.
Do not add a callback to a MetadataRetriever call in ExoPlayerBackend.
This fixes an issue where if an error occurs while a future completes,
the app will crash entirely. This is because Futures run on a different
Executor and thus exceptions will not bubble up to Indexer.
Make the detail UIs respond to automatic rescanning events.
This currently has no effect, but is instead a preparation step for the
seamless addition of automatic rescanning.
Make IndexerService only auto-index music when there is no library AND
no loading has occured.
This resolves an issue where if IndexerService dies after a failed
index, IndexerService would try to index music regardless, as there was
no library present.
Add support for excluding directories on other volumes, at least from
Android Q onwards.
Previously, Auxio only supported excluding the primary volume. This was
mostly out of laziness, as the excluded directory implementation was
shamelessly copied from Phonograph. This commit completely refactors
the excluded directory system, dumpstering the old database (which was
overkill anyway) for a new system based on SharedPreferences that is
actually capable of handling external volumes.
Now, limitations regarding external volumes still apply below Android
Q, as the VOLUME_NAME field does not exist on those versions. However,
this should resolve at least one major complaint regarding the
excluded directory system. Now theres just all of the other complaints.
Resolves#134.
Fix an issue with highlighting in the detail UIs taht stemmed from the
ViewHolder position being cached.
Resorting could have changed the ViewHolder position, so caching it
will result in ViewHolders being incorrectly updated.
Rework genre parsing to properly align with the ID3v2 standard.
The ID3v2 genre specification is weirdly complex. Auxio ignored most
of that and just parsed out the most common cases for genres (digits
and (digits)). For the sake of completeness, rework Auxio's genre
parser to handle the weirder cases like RX/CR, multiple values,
and escaping, with an implementation roughly based on Mutagen's
genre parser.
Improve Indexer's state management by splitting up the current loading
state and the last response.
This is intended to resolve a bug where if the UI task and
IndexerService are both killed, the Indexer state would become
indeterminate and the library would not show. Resolve this by keeping
track of whatever the last completed state was and falling back to it
whenever the loading process is canceled.
Add a dedicated service towards the loading of the music library.
This new service was created for two reasons:
1. Music loading is slow and resource-intensive, so putting it on the
ViewModel layer just didn't seem right and made it vulnerable to the
OS simply stopping the loading process.
2. For automatic rescanning [#72], there must be something watching
the music library and waiting for a change in the background. This
would require a service as that is probably the least insane way to
do that kind of background work.
I have no garuntees how viable the service might be. If anything, it
might be halted by some insane android restriction or issue that
makes it more or less impossible to use for most apps, and I will have
to largely drop truly automatic rescanning.
Rework loading management into a new object, Indexer, which should act
as the base for all future loading changes.
Indexer tries to solve a two issues with music loading:
1. The issue of what occurs when tasks must be restarted or cancelled,
which is common with music loading.
2. Trying to find a good strategy to mediate between service and
ViewModel components in a sensible manner.
Indexer also rolls in a lot of the universal music loading code
alongside this, as much of MusicStore's loading state went unused
by app components and only raised technical challenges when reworking
it.
Rework genre ordering to be alphabetical based on album, but without
all of the mosaic being taken up by one artist.
With the ordering changes that were done previously, genre images
greatly differed compared to previously. May as well use this breakage
as an oppertunity to improve genre ordering. In this case, we want to
order albums alphabetically, as usual, but we also want to prevent
one artist from taking up the whole mosaic. Fix that by deduplicating
artists in the set of grouped albums.
Add an indicator to gague the current music loading progress.
This is actually a lot harder to implement than it might seem, not only
due to UI state issues, but also due to the fact that MusicStore needs
to keep it's state sane across a myriad of possible events that could
occur while loading music. This system seems like a good stopgap until
a full service-backed implementation can be created.
Apply the notifyItemChanged fix everywhere by making it an explicit
part of the RecyclerView framework.
This way, implementing future selection and rewrite behavior will be
much easier, as the payload argument is available in every adapter
implementation.
Fix two major highlighting bugs based around the janky and stupid way
I would handle highlighting previously.
Previously, I would index the views of a RecyclerView in order to
highlight viewholders. In retrospect this was a pretty bad idea,
as viewholders could be in a weird limbo state where they are bound,
but not accessible. I mean, it's in the name. It's a Recycling View.
Fortunately, google actually knew what they were doing and provided
a way to mutate viewholders at runtime using notifyItemChanged.
And the API actually makes sense! Wow! Migrate all detail adapters
to a system that uses notifyItemChanged instead of the terrible
pre-existing system.
Fix a state restore issue that would cause the parent to restore
incorrectly.
At some point, I accidentally used the index for the PlaybackMode field
when restoring the playbackState. This resulted in the playback mode
effectively reverting to ALL_SONGS and causing a number of subtle
issues.
Further refine the Indexer and ExoPlayerBackend implementations.
These fixes were primarily focused on ensuring stable grouping through
stable sorting order, and more graceful handling of edge cases in
ExoPlayerBackend.
Fix a regression where media button controls would no longer work
with GadgetBridge.
In 4a79de4, I assumed that my code was redundant, as there should be
some kind of reciever handling media button events already. I was
completely wrong. Re-add the reciever code (with extra checks) to
make controls work again.
Switch from LiveData to StateFlow.
While LiveData is a pretty good data storage/observer mechanism, it has
a few flaws:
- Values are always nullable in LiveData, even if you make them
non-null.
- LiveData can only be mutated on Dispatchers.Main, which frustrates
possible additions like a more fine-grained music status system.
- LiveData's perks are exclusive to ViewModels, which made coupling
with shared objects somewhat cumbersome.
StateFlow solves all of these by being a native coroutine solution with
proper android bindings. Use it instead.
Move the loading screen into the home view.
Previously, we would use a Snackbar to track the music loading state.
This ended up being a pretty stupid and buggy idea, and would get even
worse with the new music loader changes. Instead, we re-implement the
loading screen into the home view to generally be more sane and
extendable compared to previously.
Make addCallback calls (or similar) initalize the caller by calling the
specific callback methods.
This is primarily intended as a fix to an issue where the music library
would actually reload during a warm start. This is extremely bad, but I
hope it doesn't make the app too unusable until the next version.
Add an ExoPlayer-based metadata backend.
This backend finally allows Auxio to parse metadata internally, which
has been a highly requested feature given how many unfixable MediaStore
issues it would fix.
However, this is not fully ready for production yet. The loading
process becomes much larger with manual parsing, the current
implementation still allocates picture metadata (terrible for
efficiency), and there is no good indicator in the app to keep
track of music loading.
As a result, this backend is disabled until it can be fully integrated
into Auxio's architecture.
Move out the MediaStoreCompat interface into a full interface called
Backend.
In preparation for direct metadata parsing, it would be useful to
create some kind of object system to properly handle the capabilities
of each metadata indexing mode. Backend fulfills that by allowing
each object to implement their own query and then loading routine.
This system is designed somewhat strangely. This is firstly because
the ExoPlayer metadata backend will have to plug in to the original
MediaStore backend, so making methods more granular allows the
ExoPlayer backend to avoid some of the stupid inefficiencies from
the actual MediaStore backend, such as the genre loading process.
We also want to separate the steps of loading music in order to
more adequately show the current loading process to the user in
a future change.
Implement a safe slider wrapper that does not crash with invalid values
as often.
Slider is a terrible component that is not designed with Auxio's
use-case in the slightest. Instead of gracefully degrading with invalid
values, it just crashes the entire app, which is horrible for UX.
Since SeekBar is a useless buggy version-specific sh******ed mess too,
we have no choice but to wrap Slider in a safe view layout that
hopefully hacks with the input enough to not crash the app when doing
simple seeking actions.
I hate android so much.
Resolves#140.
Add disc number sorting to sorts that originally sorted by track.
Forgot to add disc sorting to the other sort modes when adding disc
number support. Fix that.
Create separate routines to parse disc and track numbers in the most
optimal manner.
On API 30 (Android R) and above, ensure that we are using the superior
CD_TRACK_NUMBER and DISC_NUMBER database fields, while below API 30,
stick with the normal TRACK field.