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.
Completely rework app typography.
Today I found out that inter has a tool that allowed you to generate
line spacings for a particular font size. Several hours later, I
regenerated the entirety of Auxio's typography to use this new system.
Moreso, I also tried to eliminate some of the non-standard text styles
that I was using prior. That failed. Mostly there's two edge-cases
regarding title bolding and the playback view that I simply cannot
work through right now, since M3's typography system is horribly
restrictive.
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.
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.
Add a shortcut to shuffle all songs.
This is likely the only static shortcut Auxio will have. Top tracks
and recently added are completely useless for me, so I will never
add them. I may add more dynamic shortcuts for recently played items,
however.
Note that we use a basic black shuffle icon here. I will not add icon
customization to these shortcuts.
Fix a visual issue with the queue animation where the playback view
will still slightly show.
This was caused by the lack of a background in the queue fragment UI.
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
Completely rework the excluded directory system into a new
"Music Folders" system.
This is implemented alongside a new "Include" mode. This mode
allows the user to restrict music indexing to a parsicular folder.
I've been reluctant to add this feature, as having two separate
options seemed bad. This resolves it by effectively packing whether
to include/exclude directories into a single option.
Resolves#154.
Use basic scroll indicators when a dialog shows a list.
Mostly for material guidelines. Excluded dialogs and int pref dialog
have not been modified, as I am still working on revamping those.
Make it so that the rounded covers option is not dependent on the show
covers option.
Rounded covers has no relation to whether to show covers (at least not
anymore with the new cover style), so it makes no sense to disable it
when show covers is turned off.
Resolves#152.
Remove malformed songs that have a size of 0 bytes, but are still
present in MediaStore.
This issue only seems to occur when files are transferred via MTP, but
are not loaded due to storage issues.
Add a new view called ImageGroup that will handle all advanced image
hacks from now on.
This includes the indicator (which is now animated), any selection
indicators, and the weirdness of the album song image. All of that
is now handled by ImageGroup. This is the culmination of probably
a day and a half of wrangling with android insanity and having to
remove a lot of what I liked about the indicator in order to make
this work on a basic level.
The only major bug I am currently aware of with this is that the
indicator is bugged out on Lollipop devices due to bad vectors.
Again.
I never want to do this again. I cannot believe that adding a basic
indicator took this long and required so much stupid hacks and
inefficient code. And then google wonders why android apps are so
visually unappealing and janky and laggy. Hm. Must be that devs aren't
using the brand new FooBarBlasterFlow library!
Add a playing indicator to cover art.
This is simply to improve the general aestethics of this view. Of
course, the current way I implement this is incredibly stupid and I
plan to replace it.
Rework the submitList animation to be less resource intensive and nicer
looking (at the cost of scroll positioning)
notifyDatasetChanged is slow and has no animation, but list diffing is
chaotic and basically useless outside of search. However, clearing the
adapter and then populating it with new items seems to work quite well,
albeit with the scroll position being lost sadly. Switch to that.
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 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 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.
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 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.
Revert the introduction of the thin/tiny widgets, but keep the new
cover layout I created while working on them.
There is simply no way I can cram controls and metadata within the
size bucket that the thin widget occupies. I have decided to give up
and revert the widget to it's old form.
I understand why the thin widget is not appealing. However, the sizing
at which a widget can properly accomodate a taller widget is just too
precise and not really large enough to justify it's existance.
Re-add accent customization on Android 12 and above.
Previously, I disabled accent customization since I thought they were
more or less useless with the new Material You dynamic colors system.
Turns out I severely underestimated how horribly OEMs would botch the
dynamic colors system. Guess I was blinded by my adherence to the pixel
line. Re-add the accent customization for those who do not have a good
dynamic color palette at all.
Resolves#131.
Hack around more insane lollipop bugs, such as:
- The angular auxio icon crashing the system UI
- Optimized icons being corrupted
- Setting image alpha not working properly
I really wish I could drop support for this horrible version, but I
either have to wait for a major library to drop support or for the
usage numbers to reach 1%.
Remove references to android system strings, in favor of in-house
translations.
Previously Auxio would use the `android.R.string.ok` and
`android.R.string.cancel` strings to represent Ok and Cancel
respectively, but these system strings are actually untranslated on
some devices, so it is better for i18n if we use our own strings
for such.
Add recovery code to the music indexer in the case that Android doesn't
provide the DISPLAY_NAME field.
Nominally this should never happen, but OEMs will OEM and apparently
this does happen on some devices. Try to recover by grokking DATA for
a file name.
Finalize the disc number implementation within Auxio.
This is probably one of the most widely-requested features outside
of playlisting. This implementation also adds some more fine grained
sorting modes for disc numbers in particular, which actually removes
some of the quirkiness of the Sort class.
Resolves#96.
Split off the "songs loaded" about item into it's own card called
"library statistics"
This card includes the song, album, artist, and genre counts,
alongside a total duration of the music library. This is just more
informative and useful to the user.
Resolves#121.