md: add widget module to ARCHITECTURE

Add documentation on the widget module to ARCHITECTURE.md.
This commit is contained in:
OxygenCobalt 2021-08-06 12:10:42 -06:00
parent e81d4b6d17
commit 1d828c7b0a
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 37 additions and 5 deletions

View file

@ -8,7 +8,9 @@ import org.oxycblt.auxio.settings.SettingsManager
/**
* A wrapper around each [WidgetProvider] that plugs into the main Auxio process and updates the
* widget state based off of that. This cannot be rolled into [WidgetProvider] directly.
* widget state based off of that. This cannot be rolled into [WidgetProvider] directly, as it may
* result in memory leaks if [PlaybackStateManager]/[SettingsManager] gets created and bound
* to without being released.
*/
class WidgetController(private val context: Context) :
PlaybackStateManager.Callback,
@ -22,6 +24,9 @@ class WidgetController(private val context: Context) :
settingsManager.addCallback(this)
}
/*
* Update the widget.
*/
fun update() {
widget.update(context, playbackManager)
}

View file

@ -5,8 +5,8 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.LoopMode
/*
* A condensed variant of the current playback state, used so that PlaybackStateManager does not
* need to be queried directly.
* An immutable condensed variant of the current playback state, used so that PlaybackStateManager
* does not need to be queried directly.
*/
data class WidgetState(
val song: Song,

View file

@ -166,7 +166,7 @@ PlaybackStateManager───────────────────┘
`PlaybackStateManager` is the shared object that contains the master copy of the playback state, doing all operations on it. This object should ***NEVER*** be used in a UI, as it does not sanitize input and can cause major problems if a Volatile UI interacts with it. It's callback system is also prone to memory leaks if not cleared when done. `PlaybackViewModel` should be used instead, as it exposes stable data and safe functions that UIs can use to interact with the playback state.
`PlaybackService`'s job is to use the playback state to manage the ExoPlayer instance and notification and also modify the state depending on system events, such as when a button is pressed on a headset. It should **never** be bound to, mostly because there is no need given that `PlaybackViewModel` exposes the same data in a much safer fashion. `PlaybackService` also controls the `PlaybackSessionConnector` and `AudioReactor` classes, which manage the `MediaSession` and `AudioFocus` state respectively.
`PlaybackService`'s job is to use the playback state to manage the ExoPlayer instance, the notification, and also modify the state depending on system events, such as when a button is pressed on a headset. It should **never** be bound to, mostly because there is no need given that `PlaybackViewModel` exposes the same data in a much safer fashion. `PlaybackService` also controls the `PlaybackSessionConnector`, `AudioReactor`, and `WidgetController` classes, which manage the `MediaSession`, Audio Focus, and Widgets respectively.
#### `.recycler`
@ -190,3 +190,30 @@ Shared User Interface utilities. This is primarily made up of convenience/extens
- The Accent Management system
- `newMenu` and `ActionMenu`, which automates menu creation for most data types
- `memberBinding` and `MemberBinder`, which allows for ViewBindings to be used as a member variable without memory leaks or nullability issues.
#### `.widgets`
The widget sub-module. This module differs heavily from the rest of Auxio, as widget UIs can't be controlled in the same
way that UIs in the main process can.
Widgets are controlled by two pieces of code:
- `WidgetProvider`, which provides the widget layouts to the system
- `WidgetController`, which acts as an intermediary between the Auxio process and the widget [ex. Monitoring the playback state]
The widget update process is described in this diagram:
```
WidgetController<──────────PlaybackService
│ Controls ^
│ │
│ Updates │
│ │
│ │
v Requests Update │
WidgetProvider───────────────────┘
```
When `WidgetProvider` creates a layout, it first turns the `PlaybackStateManager` instance into a `WidgetState`, which is
an immutable version of the playback state that negates some of the problems with using a shared object here. It then picks
a layout [e.g "Form"] depending on its current dimensions and applies the `WidgetState` object to that.