Fix lints that have accumulated over time.
Apparently Android Studio just...stopped using lints. For no reason. I
had to upgrade to the beta version to actually get lints.
Add a split playback UI in landscape mode.
Apparently the mere act of doing this also fixes the infurating
window inset issue I previously did either. Odd.
Use MaterialFadeThrough in the search transition and a Z-axis
transition in the detail views.
This is more semantically correct than the previous transitions.
Add a new Date class to represent both years and more fine-grained
dates extracted using the ExoPlayer metadata system.
In-app, the year is still shown, but sorting will use the new precision
when present. The MediaSession will also post an RFC 3339 formatted
date with this new precision, as the MediaSession documentation states
I should. No clue if the latter will cause any bugs with naive metadata
UIs in other apps.
Resolves#159.
Prepare support for sort tags by reworking how sortName is structured.
Instead of rawName and sortName, music must now implement rawName and
rawSortName. rawSortName will be checked first, followed by will
falling back to rawName.withoutArticle. This allows hard-coded tags to
be neatly implemented while avoiding an immediate copy.
Add automatic rescanning, for real.
This is the culmination of 6 months of work to make Auxio respond to
music updates and to research the most versatile implementation of
such. Is it the best system? No. It's actually a bit messy by necessity
in order to prevent bugs. Does it work well? Yes.
This will not be enabled by default, as it does require a battery
draining foreground service and is generally not useful for most
circumstances.
So glad to be done with this.
Resolves#72.
Move the switch from IO to Main to within Indexer itself, through
withContext.
This is much easier to work with than the previous system of a separate
"update" coroutine, which isn't really needed anymore given that I no
longer need to do IO work when sanitizing the playback state.
Rework the UI flow for music loading to be more coherent with runtime
rescanning.
The loading progress is now shown as a card on the bottom of the
screen. This way, app use is not completely crippled when the app has
to rescan the music library, albeit the shuffle button still has to
be disabled during this period.
Remove WindowInsetsCompat from the project, as it is a pile of garbage.
WindowInsetsCompat refuses to actually update the correct fields when
you transform it back into a WindowInsets. This makes it impossible to
use in Auxio. The fact that Google decided to make such an
overengineered wrapper to some version-specific methods is an absolute
joke. All you needed were some extension functions, but no, let's make
an entire wrapper class filled with so many gotchas as to be unusable.
Do not use collectImmediately when recreating tabs in the home menu.
This resulted in an issue where the ViewPager would not update to
reflect the new tab layout.
Force LTR on timeline controls, as per the Material Design guidelines.
The guidelines state that while "directional" UIs should be LTR/RTL
depending on locale, "timeline" UIs should always by LTR, as the
direction of time is universal. Auxio did not do this, and so the
timeline controls would be RTL on other elements. Fix this by forcing
LTR on the UI elements that correspond to timelines.
Now, this is not the best system. To ensure that the rest of the layout
remains sane, much of the directional views have to be wrapped in a
redundant layout, which is somewhat in-efficient. However, the impact
seems to be at least negligable.
Rework Sort again into a new class that leverages a better Mode design
and static comparator instances.
This somewhat improves efficiency, but is also far easier to work with
and has far less footguns with adding new sorts.
Add new shortcut utilities for collecting StateFlows in a safe manner.
The priamry addition here is collectImmediately. collectImmediately
just calls block with the existing value initially, which helps remove
a good amount of bugs regarding state initialization. Sure, it is a bit
inefficient given that it will also initialize on startup, but this is
okay.
The other utilities are the same, but simply remove the launch
boilerplate.
Add a new "Detail playback mode" option that allows one to configure
what selecting a song will do in an album/artist/genre.
This is mostly a clone of the prior setting, just in a new context.
Resolves#164.
Add a utility to easily work with lifecycle-dependent fragment objects.
This reduces the code duplication required to maintain objects that
would leak after the destruction of a fragment. We normally would not
do this as a delegate, as that usually entails some lifecycle wizardry
that can easily break and crash the app in esoteric situations.
However, this this just extends the normal lifecycle without watching
any state, it seems to be pretty safe to use.
Rework the preference classes to reduce the horrible bloat of the
recursivelyHandlePreference function.
This was mostly implementing new methods into IntListPreference and
adding a new preference to represent the weird, "generic" dialogs that
are used at points. While some preferences still need to be tweaked in
recursivelyHandlePreference, it is nowhere near as bad as it was prior.
Revamp the shared object SettingsManager into a standalone utility
called Settings.
This makes many things easier in Auxio. It completely unifies the key
format that we use (Android Strings instead of Java consts), eliminates
the pretty dumb initialization method that we use, and eliminates the
dubiousness of holding a Context-related utility in a global field.
The only cost was having to migrate even more ViewModels to Android
ViewModels. Whatever.
Use ServiceCompat.stopForeground instead of stopForeground.
This is preliminary preparation for Android 13. I can only change SDK
versions however when the Android Gradle Plugin makes a new release
though.
Remove the animated indicator, replacing it with a static one.
I wish I could have kept this, but once again android is a sh******ed
mess and makes it impossible to dynamically animate something depending
on the playing state. It will restart the animation, ignore calls to
stop, or just flat out now run the code path in the first place due to
race conditions.
Introduce MenuFragment in order to replace ActionMenu.
ActionMenu was a terrible class filled with hacks. Introduce a new
fragment called MenuFragment that enables the same features, plus:
1. Requiring consumers the specify the menu, which prevents issues
from one-size-fits-all menus (unless absolutely necessary)
2. Fixing an issue where multiple menus appear at once
Only show codecs in the "format" field, if we are able to extract them.
This is primarily for consistency, as there is no way for us to
determine the container format outside of an extension (which could not
be sane).
Completely rework the way Auxio handles icons.
This is mostly two changes:
1. Removing ImageButton/StyledImageButton for MaterialButton. This is
done by abusing MaterialButton's theming options to make it only show
an icon.
2. Standardizing icon sizes into small, medium, and large categories.
Small is the default, Medium and Large are for edge-cases like the
playback icons which look horrible at 24dp.
3. Abusing the Toolbar to make it follow Material 3 guidelines. This
mostly involved removing the strange icon sizing and correctly padding
the view.
4. Reworking the playback bar to use more, smaller icons, making it
more like a Toolbar in the process (which I like).
Supply a view to WindowInsetsCompat.toWindowInsetsCompat through all
calls in the app.
This does nothing, but it would resolve future bugs if I were to use
the most exotic window inset types.
Make the home toolbar collapse on scroll.
I was planning to implement this back in 2.0.0, but visual bugs stopped
me. Now, knowing how much space the the Toolbar + Tab combination takes
up on smaller devices, I think it would be better to have this in
general.
Rework PrimitiveBackingData into SyncBackingData.
Google says that you should not use DiffUtil on the main thread, as it
is far too slow. In practice, the time it takes to diff is negligable,
even more so when costly diffs are filled in with a replace call
instead. Not only that, but switching to a synced list differ fixees
the horrible nightmare that is the queue adapter. Generally a win-win
for most use-cases in Auxio.
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.
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.