Revert the changes I made in 0474940ee3
and return to the hybrid layout + inset system.
The big issue is edge effects and touch events. I need to properly
clamp edge effects to the padding, but that also requires me to use
stretch edge effects everywhere to prevent weird visual isuses. This
may happen in the future in RecyclerView 1.3.0, but development on such
has been minimal. Meanwhile, touch events will be intercepted by the
now overlapping view if one clicks the wrong portion of the bar.
Nothing I can do given how touch events are intercepted by the bottom
sheet, at least right now.
More feasible to keep the current system and mitigate whatever issues
are present there.
Update transitions in the home fragment to X-axis.
I noticed a visual issue in the detail transition in the existing
version stemming from how the main fragment's drawing is clipped by
the bottom sheet, resulting in a less-than-ideal Z-axis transition.
While I wanted to fix this by attempting to switch to inset based
bottom sheet management, I still need to wait for more changes in
order to successfully pull that off, and hence I'll be reverting it
soon.
Moving these transitions to X-axis prevents this visual issue while
still being roughly semantically similar.
Add an item type indicator to the top of the detail header.
This is primarily for release type functionality, but also makes it
more clear the item one is looking at.
Do not do a measure + inset method with BottomSheetContentBehavior,
instead, try to re-apply window insets to adapt with the bar instead.
This fixes a lot of view clipping issues that made motion transitions
non-ideal and prevented a rounded playback bar. Only remaining issue is
RecyclerView instances, which need to be further reworked to resolve
scroll issues and edge effect problems.
Fix an accidental usage of Material3 text styles instead of Auxio.
Left-over from the testing app I did for the new bottom sheets. Stuck
around through some means.
Remove the textSafe method, as it is functionally useless.
textSafe relied on a dumb 1.0.0 thing where I used wrap_content on
text views. Now it just causes relayouts for no good reason.
Remove EdgeCoordinatorLayout in favor of using fitsSystemWindows when
needed.
EdgeCoordinatorLayout was derived from a misunderstanding about how
window insets worked. Remove it.
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.
Leverage min heights for the playback layouts instead of the land
modifier.
This prevents an issue where some split-screen displays won't use the
correct "compact" layout.
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.
Make bottom sheets request window insets when they are laid out.
For some insane reason, bottom sheets are just not given window insets
when the device is rotated in the detail view. Appaently requesting them
fixes it all of a sudden.
Check if the playback state still has not been initialized once we
restore.
This prevents one from playing a song while the restore task is
on-going and then having it overwritten by the restored state.
Use MaterialFadeThrough in the search transition and a Z-axis
transition in the detail views.
This is more semantically correct than the previous transitions.
Remove useless id fields from Headers, replacing them with vlaues
related to their string resource.
String resources and disc numbers are more or less garunteed to be
unique in Auxio's context.
Indicate the currently playing item in the queue list.
The item is still disabled, however it's also simultaniously activated
now, which allows it to indicate that it is playing.
Fix two issues where Auxio's widget could not be resized to a single
cell, and another where covers would not load into the widget.
The first is caused by a random, subtle change that completely changed
up the minHeight size calculation regarding widgets. Thus, we need to
lower it for android to recognize it still as 1 cell. I cannot believe
we can't just specify the specific minimum grid size that our widget
takes up, like you know, iOS did, nearly a decade after widgets were
first added in Android.
The second is an absurd race condition stemming from me hitting the
RemoteViews memory limit. Turns out my cover bitmaps were simply too
big. Getting them below the limit requires me to resize them to a puny
~500 pixels. Why can't we just render our own views into our widget?
You know, like iOS did, nearly a decade after widgets were first added
to Android.
Nah, screw modernizing the broken widget API. Let's just vaguely copy
iOS widgets because we have to while not fixing a single issue plaguing
widget development on this OS. That way some google engineer can get
promoted faster.
Add the ability to see (but not edit) previous items.
This completes the new playback UI I've been working on for about 2
weeks now. I pray that there is no insane unfixable bug with this,
please please please please please
Fix more bottom sheet issues regarding the queue sheet.
Guess I brought it upon myself for nesting bottom sheets like this in a
way that I doubt the behavior expects.
Fix an issue on some devices where bottom sheet transitions would not
initialize correctly.
Turns out I can't try to do transitions using the callback and simply
initalizing them on startup. Apparently on some devices,
CoordinatorLayout will simply not lay out until some arbitrary point
past onResume. This breaks our transitions.
Fix it by using a pre-draw listener instead. I cannot believe I have to
do this.
Re-implement the queue, now leveraging a bottom sheet too.
This makes the queue much easier to open, and actually plays along with
the new transition system. I really hope this doesn't have a stupid
gotcha that ruins the UX. Please. Please. Please.
Use BottomSheetBehavior with the playback sheet.
This is the result of two weeks of painful hacking to get a working
implementation that did not immediately have a brain aneursym. It
also requires me to still vendor BottomSheetBehavior for the time
being. However, this greatly reduces technical issues on my end and
allows the addition of new playback UI concepts, while still
retaining the UI fluidity of prior.
Temporarily remove queue navigation, as it can no longer really fit
with the new transitions.
This will eventually be replaced with a queue bottom sheet, implying
that I can abuse one into working.
Unify the background state layers of the entire app by overriding
colorControlHighlight.
Lots of components still use it, so it's beneficial to make it
consistent with the rest of the app theming.
Rework the queue internally to decouple the queue from playback and
better respond to reshuffling.
This is being implemented under the assumption that I will be
implementing the sliding queue eventually.
Add the ability to jump to arbitrary points in the queue.
This comes at the cost of the long-press option to move items, since
they simply cannot co-exist without visual issues.
Hack around an issue where the notification position will not update if
one seeked while the player was paused.
This is the best implementation I can do that will not result in the
notification getting excessively rate-limited.
Expose the queue in the MediaSession, at least I hope.
The queue is still not mutable. Don't feel comfortable implementing that
until I rework the in-app queue UI.
Add an option to clear the currently saved playback state.
This does not clear playback entirely, but rather remove the saved
state so that it's not restored on the next startup. This is generally
the cleanest solution compared to allowing state restore to be toggled,
which opens up a bunch of race conditions.
Resolves#107.
Modify ExoPlayerBackend to handle the presence of multiple vorbis tags
for a particular key.
This is allowed by the spec and heavily leveraged by programs like
Picard. It also opens the door for better artist functionality, but
that is incredibly complicated and something I don't want to implement
right now.
Rework album types into release types, with additional support for live
albums, remixes, and mixtapes.
This is not a complete implementation, nor is it meant to be. I don't
want to add technical complexity handling Remix Compilations or
DJ-Mixes unless there is demand.
Add release type support to the media indexer.
This allows EPs, Singles, and Albums to be distinguished from
eachother. Auxio's implementation will use the MusicBrainz tag for
ID3v2 (Falling back to GRP1, as that is used sometimes), and will use
RELEASETYPE for vorbis comments.
Update MDC to the alpha version in order to use some extra features.
I was planning to switch to the new MaterialSwitch, but alpha03 has
this insane crippling issue with ripples that blocks such. Use alpha02
and prep the app for the addition of the switch.
Lowercase music names when hashing them to prevent drift stemming from
grouping.
The addition of the song may change the case of an artist if such
mitigations are in effect. To prevent such from invalidating music
hashes, we take the lowercase of every name hashed.
Don't take the app widget host padding into account when trying to
calculate the widget sizing.
Doing such produces bad results, at least on my devices. At least, it
does now for some reason.
Fix an issue on some devices where the delayed actions system would
not work on startup.
Apparently onStart can be called several times with the same intent.
No, I am not joking. What the actual hell. This would cause any
delayed action other than Restore to be overwritten. The only hard
rule about android is that there are no rules. I hate this platform
so much.
Set the enforce*BarContrast methods to false above API 29, so we can
use fully transparent navigation and status bars.
Previously, we used a mostly transparent color for such, but now, we
can use a completely transparent color without it being changed to
match contrast.
Update id hashing to correctly handle null artists and take discs
and durations into account.
Note that we try not to hash values only obtained with the ExoPlayer
parser, as those could feasibly change if the setting was toggled,
thus causing the playback state to wipe.
Make the search algorithm take in account the raw sort name and file
name when searching.
This allows the user to search for a particular song without typing in
a unicode/non-ideal title, instead typing in a latinized sort name or
suitable file name.
This does make Auxio's search a bit more fuzzy, but it still gets the
job done.
Resolves#184.
Related to #172.
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.
Implement sort tag support in the ExoPlayer backend.
Sort tags for grouping is still derived from the templates. Album
artist sort tags are only picked if one is present. System might be
a bit buggy at the moment given that it messes with grouping/sorting
a little.
Resolves#172.
Added date added sorting to albums as well.
This implementation picks the earliest song in an album that was added
to the library and then uses that for sorting.
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 a "Last Added" sorting option to the home UI's song list.
I don't know if there is any demand for last added in other contexts.
That will be resolved later.
* Translated using Weblate (German)
Currently translated at 100.0% (189 of 189 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/de/
* Translated using Weblate (Czech)
Currently translated at 100.0% (193 of 193 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/cs/
* Translated using Weblate (Dutch)
Currently translated at 100.0% (193 of 193 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/nl/
* Translated using Weblate (Turkish)
Currently translated at 97.4% (188 of 193 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/tr/
* Translated using Weblate (Russian)
Currently translated at 67.8% (131 of 193 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/ru/
* Update translation files
Updated by "Cleanup translation files" hook in Weblate.
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/
* Added translation using Weblate (Japanese)
* Translated using Weblate (Czech)
Currently translated at 100.0% (197 of 197 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/cs/
* Translated using Weblate (Czech)
Currently translated at 100.0% (198 of 198 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/cs/
* Translated using Weblate (Turkish)
Currently translated at 95.9% (190 of 198 strings)
Translation: Auxio/Strings
Translate-URL: https://hosted.weblate.org/projects/auxio/strings/tr/
Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: Fjuro <fjuro@seznam.cz>
Co-authored-by: 2hot2exist <pyramidex@protonmail.ch>
Co-authored-by: metezd <itoldyouthat@protonmail.com>
Co-authored-by: Егор Ермаков <eg.ermakov2016@yandex.ru>
Remove the excluded directory migration code, as it causes far more
issues than it fixes.
Due to an unfixable logic bug that occurs when trying to read the
setting, Auxio will always try to migrate the database when there is
no music folders, causing a hang in some situations. Fix it by just
removing the migration.
Add an abstraction over the generation system called GenerationGuard.
This allows cheap cooperative threading to be implemented consistently
in many places.
Hide the new quality tags option for now.
This is not because I wanted to, but rather because of me wanting to
reduce the amount of bugs I will likely be thrown due to the release
of automatic rescanning.
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.
Edge case I thought existed did not. PlaybackService must have saved
before dying, and thus if it did not foreground after a sanitization,
the saved state would still sanitize in a similar manner.
Save, but do not read the playback state when sanitizing.
Turns out there is an edge-case where we want to save the state. Still
keep the runtime sanitization, as that greatly reduces the time it
takes to rescan the library.
Do not save the playback state when sanitizing.
After some thought, there is no situation where re-saving the playback
state is desirable. A previously saved state will be consistent with
a sanitized state, and there is no need to save when the service is
active. Thus, save on speed and reduce insane race conditions by just
sanitizing the current runtime state and not saving at all.
Remove the ripple resources and replace them with their system
counterparts.
This is to remove redundancy in-app and make the widget more consistent
with other android widgets.
Finally unify all icon activation states under the new grade modifier
in Material Symbols.
This provides similar clarify to the dot/greyed state, but without
inconsistent meanings. The shuffle icon did have to be bolded a little
more though, as the grade did not seem to do much.
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.
Revert the optional rounded corners on the bottom sheet.
It was causing too many bugs to be a sensible addition. I will only add
it if Google moves WindowInset application to layout time AND only on
devices with the stretch overscroll implemented.
Audit usages of Synchronized throughout the app to prevent deadlocks.
This is primarily composed of not making long-running work
synchronized, instead only making mutations and reads synchronized.
This does cause minor issues, such as during a sanitization event
the playback state could be feasibly saved, changed, and then restored
back to the previous state unintentionally. However, preventing
deadlocks is generally better than trying to fix those.
Use the @Synchronized annotation instead of synchronized.
Makes my ability to manage thread-safety on the shared objects much
easier. Because I don't have to think about what I should guard
and what I shouldn't.
Finally enable runtime rescanning, opening the door for a ton of new
features and automatic rescanning later on.
More work needs to be done on making the shared mutable state in-app
safer to use.
Improve the indexer callback system to be more coherent and efficient.
This delegates the old Callback role to a new singular Callback and
Controller roles. IndexerService also handles the loading process
more gracefully, reducing the amount of time music loads take.
Make notification updates entirely reliant on the MediaSession.
Android 11 and onwards automatically populate the notification with the
MediaSession state. This apparently conflicts with updating the
notification in some cases, resulting in the incorrect song being
shown. Fix this by not populating the notification from Android 11
onward and only posting it when the MediaSession state was set.
Resolves#179.
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.
Rework the rounded covers option into a new "Round Mode" option.
This commit extends the rounded corners configuration to now the
widget, thus making the setting apply now to covers, the bar, and
the widget configuration. This makes a naming change useful.
Further rework the button layout to be alike to other modern widgets.
This changeset transforms the play button into a FAB-ish thing,
makes spacing coherent between the uses of each layout, and adds
spacers to make the buttons layout in a more appealing way.
Update the library update process to be on a co-routine, updating
callbacks on the main thread.
For some insane reason, the Main dispatcher used normally when
loading music just disappears sometimes. This leads to unpleasent
crashes as callbacks expect to be called on the app thread, not
any background threads.
Fix this by forcing the Main dispatcher during the update process.
This requires the music update process to also run on a background
thread, albeit that will be useful for automatic rescanning late ron.
Completely rework Auxio's iconography based on the new material symbols
icon set.
This does the following:
1. Switches the sharp + filled icon style to an outlined + round icon
style.
2. Removes 32dp icons from everywhere except the playback panel.
This does not:
1. Actually handle optical sizes right. This is going to take some more
work to make it harmonious with the current UI.
2. Update margins in some places to be harmonious with the new icons.
This is also going to take some more work to do properly.
Rework the bottom sheet layout process to accomodate the new rounded
corners and be far more efficient.
This removes the weird content layout code and moves it into the inset
code, which not only allows content to show in the corners, but also
allows us to minimize the amount of layouts that we normally perform.
Make BottomSheetLayout apply rounded corners when rounded covers is
enabled.
Draggable elements should be rounded, not straight, so this simply
makes this consistent. It does have one visual error as it stands,
stemming from the layout code allocating space for the bar and thus
clipping certain content. I hope to fix this soon.
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.
Fix several issues with the bottom sheet implementation, mostly
relating to what occurs when the bar is hidden.
Previously, if the bar was hidden and then re-shown, it would not be
visible, and you could override a hidden event with another tap. These
are now both resolved by removing a stray visibility assignment and
replacing the old drag checks with a new isDraggable attribute.
In the future, I hope to abuse BottomSheetBehavior into not being a
pile of garbage and replace this system once and for all.
Override isActive to control when the ReplayGain engine should
manipulate audio.
This makes the system much more efficient, as we can side-step a
useless copy when ReplayGain shouldn't be applied.
Remove the TitleMidLarge style, replacing it with more Material3
attributes.
This finally removes all of the non-standard text styles. There is
still the two TitleMedium styles, but this is considered okay.
In the playback view, TitleMidLarge has become TitleLarge, which
honestly works quite well, as the same text styles are used in the
detail views.
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 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.