Skip to main content

3.0 Work in Progress 6: Mini Player

This update mainly focuses on the addition of the mini player to the bottom of the library view (and will also be on other views where it makes sense) but I did also make some improvements in the play / pause animation.



Above shows the new mini player.  Just like every other view so far, the metadata portion will be customizable and you will be able to choose how many buttons are shown.   Right now you can choose between prev track, play/pause, and next track.  I may open it up to some of the other media actions like shuffle / repeat but i havent decided on that yet.

In the WIP4 post I had shown off a little chunk of the code that added a bunch of "behaviors" to a view.  The behaviors contain all the common code for a particular behavior of a UI view.  This allows me to rewrite the same (or very similar) chunks of code for different UIs.  GMMP 1/2.x was loaded with repeated code despite my best efforts to refactor.  Anyway, since the mini player shares a lot of the same abilities as now playing, I created 2 new behaviors: PlayingInfoBehavior and MediaButtonBehavior.

So here are the behaviors for the Library view:


view?.let {
            addBehavior(LifecycleBehavior::class, StatusBarBehavior(context, it))
            addBehavior(LifecycleBehavior::class, ToolbarBehavior(this@LibraryPagerPresenter, it))
            addBehavior(LifecycleBehavior::class, PlayingInfoBehavior(context, this@LibraryPagerPresenter, it, state))
            addBehavior(LifecycleBehavior::class, MediaButtonBehavior(context, this@LibraryPagerPresenter, it, state))
            addBehavior(FragmentContainerBehavior::class, FragmentContainerBehavior(it, state))
            addBehavior(MenuBehavior::class, HasMenuBehavior())
        }


I now set up the state of the library view for the above screenshot:


state.metadataLinesModel = MetadataLinesModel(theme).apply {
            addMetadataLine("<align=left><typeface=sans-serif><size=16>%tr%")
            addMetadataLine("<align=left><typeface=sans-serif><size=12><color=secondary>%ar%")
        }

state.buttonDefinitions = mapOf(R.id.miniPlayerPlayPause to
                                                MediaButtonDefinition(-1, R.drawable.ic_gm_pause_to_play, 0, MusicControlEvent.PLAY_PAUSE, theme.iconColorNormal),
                                        R.id.miniPlayerButton1 to
                                                MediaButtonDefinition(0, R.drawable.ic_gm_skip_previous, 0, MusicControlEvent.PREVIOUS_TRACK, theme.iconColorNormal, View.GONE),
                                        R.id.miniPlayerButton3 to
                                                MediaButtonDefinition(1, R.drawable.ic_gm_skip_next, 0, MusicControlEvent.NEXT_TRACK, theme.iconColorNormal, View.GONE))

The first part defines how the metadata is going to display and the second part defines the media buttons.  Tells it what icon to use, the size, the action that will happen on press, the color, and finally the visibility.  This is all "hardcoded" right now but will eventually hooked up to the preferences making it really easy to customize.


Small change in the code here to get the 3 buttons:


state.metadataLinesModel = MetadataLinesModel(theme).apply {
            addMetadataLine("<align=left><typeface=sans-serif><size=16>%tr%")
            addMetadataLine("<align=left><typeface=sans-serif><size=12><color=secondary>%ar%")
        }

state.buttonDefinitions = mapOf(R.id.miniPlayerPlayPause to
                                                MediaButtonDefinition(-1, R.drawable.ic_gm_pause_to_play, 0, MusicControlEvent.PLAY_PAUSE, theme.iconColorNormal, View.VISIBLE),
                                        R.id.miniPlayerButton1 to
                                                MediaButtonDefinition(0, R.drawable.ic_gm_skip_previous, 0, MusicControlEvent.PREVIOUS_TRACK, theme.iconColorNormal, View.VISIBLE),
                                        R.id.miniPlayerButton3 to
                                                MediaButtonDefinition(1, R.drawable.ic_gm_skip_next, 0, MusicControlEvent.NEXT_TRACK, theme.iconColorNormal, View.VISIBLE))


Now playing is now configured the same way:


override fun onViewAttached()
    {
        super.onViewAttached()

        view?.let {
            addBehavior(LifecycleBehavior::class, ToolbarBehavior(this@NowPlayingPresenter, it, false))
            addBehavior(LifecycleBehavior::class, PlayingInfoBehavior(context, this@NowPlayingPresenter, it, state))
            addBehavior(LifecycleBehavior::class, MediaButtonBehavior(context, this@NowPlayingPresenter, it, state))
        }
    }

    private fun createState()
    {
        //Read state
        val theme = GMThemeEngine.getInstance(context).currentTheme
        state.metadataLinesModel = MetadataLinesModel(theme).apply {
            addMetadataLine("<align=center><typeface=sans-serif-medium><size=24>%tr%")
            addMetadataLine("<align=center><typeface=sans-serif-medium><size=20>%ar%")
            addMetadataLine("<align=center><typeface=sans-serif-medium><size=20>%al%")
        }

        state.buttonDefinitions = mapOf(R.id.npPlayPause to MediaButtonDefinition(-1, R.drawable.ic_gm_pause_to_play_circle_outline, 0, MusicControlEvent.PLAY_PAUSE, theme.accentColor),
                                        R.id.npMediaBtn1 to MediaButtonDefinition(0, R.drawable.ic_gm_repeat, 0, MusicControlEvent.TOGGLE_REPEAT, theme.iconColorNormal),
                                        R.id.npMediaBtn2 to MediaButtonDefinition(1, R.drawable.ic_gm_skip_previous, 1, MusicControlEvent.PREVIOUS_TRACK, theme.iconColorNormal),
                                        R.id.npMediaBtn3 to MediaButtonDefinition(2, R.drawable.ic_gm_skip_next, 1, MusicControlEvent.NEXT_TRACK, theme.iconColorNormal),
                                        R.id.npMediaBtn4 to MediaButtonDefinition(3, R.drawable.ic_gm_shuffle, 0, MusicControlEvent.TOGGLE_SHUFFLE, theme.iconColorNormal))

    }

Here is a screenshot of the play pause in now playing using the icon from the mini player.  I plan on also adding the other play icon inside the filled circle (in addition to the current play with the circle outline.


Finally here is a video of everything in action.  The animations / transitions didnt seem to record as smooth as it appears on the device, so just keep that in mind.  I do most of my testing on a galaxy s3 running 7.1.2 and an original moto x running 5.1, so if things look smooth on those old devices they should be great on the newer ones.  This video also shows a bug with the 3 dot menu getting shifted to the left a bit when coming back to the library view.  I havent really looked into that much but it'll get fixed.. no worries.


I also want to note that when 3.0 is finally released I do think I will add 2 other options for how now playing looks.  One being the colored toolbar on top, with the album art underneath it taking up all the space between the toolbar and the metadata.  The other being smaller album art centered around a blurred background generated from the album art.  Some other players use that look and i really like it.  Plus it will be a compromise for current users of the holo themes with the blurred background

Popular posts from this blog

3.4.5 Release / Preview of 3.5

3.4.5 was just uploaded to google play and should be rolling out over the next few days. Changelog: 3.4.5 (2023-08-29): Added Dutch translation Fixed crash editing rules in rule groups Disable IAP donation options if Full Version Unlock has not been purchased to prevent confusion Other changes since 3.4.0: Added Finnish translation and updated other translations Added donation options to the purchase settings area Fixed crash when trying to bookmark / unbookmark currently playing song Fixed Finnish not showing up in the language select Fixed other various crashes Fixed issue where rating or editing tags could potentially split the album Fixed some of the lists/grids not refreshing after changes 3.5 Preview I've been working on some new UI options planned for 3.5.  So far I've finished a new gradient background option for now playing.  There are 2 different styles (linear / radial) with 2 different color sources for each.  One source will take from the theme colors, the other st

3.4.9

More fixes.  Check out discord for info on the 3.5 alpha. 3.4.9 (2024-02-14): Fixed tab navigation returning to the wrong view on screen orientation change Fixed queue not being focused on the playing track sometimes while using tab navigation 3.4.8 (2023-12-21): Fixed backup/restore intent receiver not working with IAP unlock Fixed crash sorting playlist contents

3.4.0

Plans for 3.4 changed a bit when google announced they will be hiding apps on newer versions of android if they dont target the newer sdks.  GMMP always tries to target one of the more recent versions of android, but the unlocker has no need for that since its essentially just a license key.  As of May 1st the unlocker will be hidden on newer versions of android to those who have not already purchased.  Because of this, the focus of 3.4 was to get in app purchases working to allow users to buy the full version after May 1st.  There is a new 'Purchase' section in the settings where the unlocker can now be purchased. One other change in 3.4 is the support for the Android 13+ media controls.  They changed around how to customize them, so that is reflected in a new 'Media Controls' section of the settings. The language can also be changed for just GMMP via the system settings The changelog itself is fairly small but I did a large update of all the libraries / dependencies t