Alright this is another long one. The main goal of this PR is to implement the controller UI as defined the the UI mocks. The major feature included are:
Pause/play
Seek
Skip/previous
Volume
Repeat toggle
Song info display
Playback display
During implementation, I found the following existing bugs and resolved them:
YouTube Music observer wasn't reporting current repeat mode to the popup
YouTube Music volume slider was slow to react
Amazon Music play/pause state wasn't being reported
Since this is the first time building out any UI, I wanted to give some details into my mindset for how I built the UI.
Starting with component and logic separation, I followed a stateful vs stateless component ideology. Most components should either primarily have HTML markup (stateless) or primarily have state, logic, and layout (stateful). This is similar to the Controller/View separation commonly found in the wild.
For stateful components, I put the controller logic in a single hook to separate layout/markup from the logic.
For stateless components, I set width and height typically to 100% so that the layout component above it can dictate the sizing based on the current needs of the layout.
Global State
The new global state required for this commit were:
SongInfoContext: Listens for song info updates reported by the ObserverEmitters and updates the state for access within the UI
PlaybackStateContext: Listens for playback state updates reported by the ObserverEmitters and updates the state for access within the UI
ExpandedContext: Informs the full UI of whether the controller is fully expanded or in mini mode
Expanded Styles
One of the annoying things I wanted to point out here was how many times I had to use the expanded state. I couldn't figure out a clean way to make it so I didn't have to keep passing this prop to every styled component so it just is what it is unless you have a better idea. I alleviated it some by using the ExpandedContext instead of prop drilling from the top level and created a expandedStyle util to make it a little cleaner. That's the best I could come up with.
Icons
In order to be able to dynamically style the icons, I had to put them into JS somewhere, so I did something similar but a little better organized to what I did in YTM+ by putting all of the svg markup into an Icon component that can then easily be used and styled throughout the UI.
Overview
Alright this is another long one. The main goal of this PR is to implement the controller UI as defined the the UI mocks. The major feature included are:
During implementation, I found the following existing bugs and resolved them:
Demo Video
Implementation
Component/Logic Organization
Since this is the first time building out any UI, I wanted to give some details into my mindset for how I built the UI.
Starting with component and logic separation, I followed a stateful vs stateless component ideology. Most components should either primarily have HTML markup (stateless) or primarily have state, logic, and layout (stateful). This is similar to the Controller/View separation commonly found in the wild.
For stateful components, I put the controller logic in a single hook to separate layout/markup from the logic.
For stateless components, I set width and height typically to 100% so that the layout component above it can dictate the sizing based on the current needs of the layout.
Global State
The new global state required for this commit were:
Expanded Styles
One of the annoying things I wanted to point out here was how many times I had to use the
expanded
state. I couldn't figure out a clean way to make it so I didn't have to keep passing this prop to every styled component so it just is what it is unless you have a better idea. I alleviated it some by using the ExpandedContext instead of prop drilling from the top level and created aexpandedStyle
util to make it a little cleaner. That's the best I could come up with.Icons
In order to be able to dynamically style the icons, I had to put them into JS somewhere, so I did something similar but a little better organized to what I did in YTM+ by putting all of the svg markup into an Icon component that can then easily be used and styled throughout the UI.