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.17 and 3.5 Beta 1 Released

I was not planning on putting out any more 3.4.x updates, however google refused to approve the 3.5 beta due to some policy updates that caused the existing 3.4.x version already released to no longer be compliant.  Therefore 3.4.15-3.4.17 are basically the work I've been doing on 3.5 for the last 16 months, but with all the new features disabled.  I would like to put them through more testing before enabling to the public, hence the beta. 3.4.17 (2024-10-25): Fixed crash on android 14+ trying to verify the unlocker 3.4.16 (2024-10-24): Fixed multi select in album details highlighting the wrong item 3.4.15 (2024-10-23): Update target api level to 34 Updated dependencies Manual scans are no longer ran in a foreground service due to google's new policies Last played time added to song info pop up Fixed issue where extra space was added in artists with numbers in name Increased full search limit from 100 to 10000 results Fixed issue with files missing tags showing up in the unkno...

3.5 Released!

 GoneMAD Music Player 3.5 is finally here after about a year and a half of development.  Most of the new additions are not enabled by default but I did include a new UI preset named 'bottom' that will use the new now playing layout and the new bottom navigation mode.  Enjoy! See the Beta 1 post for more information on the new capabilities Also I recently created a Bluesky account if you want to follow to get updates:  https://bsky.app/profile/gonemadsoftware.bsky.social 3.5.x: New: Added new bottom navigation mode Added new now playing layout 3 Added gradient background option to now playing layout 2 and 3 Added new details layout for artist/album/genre/etc(Change layout via: Customize -> Layout Menu -> Layout 2).  Enabled by default Added bottom nav UI preset (named 'bottom') Updates / Improvements: Updated dependencies Tweaked existing UI presets Improved startup time Fixes: Queue should now focus on playing song when opening / returning to queue Fixed s...

GoneMAD Music Player 4.0 released and is now free!

GoneMAD Music Player 4.0 is now fully rolled out!  After 14 years since initial release as being a paid app, I've decided to try something different and switch to being free with ads.  The market is completely different nowadays compared to the early 2010s.  Ads are everywhere and users typically do not want to pay for apps / games / etc.  But don't worry, those users who previously purchased the unlocker or in app purchase unlock will continue to get an ad free experience.  New users will also have the option to purchase an in app purchase to permanently remove ads.   Note: There is a bug with 4.0 where users with the standalone unlocker may see ads when they first upgrade.  You typically fix this by just force stopping the app and restarting.  Ads should not come back after that.  Alternatively you can contact gonemadsoftware@gmail.com and I can help you out as well.  I have no intention on making users who already paid see ads. W...