all: reformat code

Reformat all project code
This commit is contained in:
Alexander Capehart 2022-12-26 19:47:27 -07:00
parent 7212700553
commit cce7b766d7
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
38 changed files with 194 additions and 203 deletions

View file

@ -36,6 +36,7 @@ audio focus was lost
- Fixed issue where the artist name would not be shown in the OS audio switcher menu
- Fixed issue where the search view would not update if the library changed
- Fixed visual bug with transitions in the black theme
- Fixed toolbar flickering when fast-scrolling in the home UI
#### What's Changed
- Ignore MediaStore tags is now Auxio's default and unchangeable behavior. The option has been removed.

View file

@ -24,7 +24,6 @@ android {
}
// ExoPlayer, AndroidX, and Material Components all need Java 8 to compile.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@ -108,6 +107,7 @@ dependencies {
implementation "io.coil-kt:coil:2.1.0"
// Material
// Locked below 1.7.0-alpha03 to avoid the same ripple bug
implementation "com.google.android.material:material:1.7.0-alpha02"
// LeakCanary

View file

@ -121,6 +121,7 @@ class MainActivity : AppCompatActivity() {
*/
private fun startIntentAction(intent: Intent?): Boolean {
if (intent == null) {
// Nothing to do.
return false
}

View file

@ -54,7 +54,9 @@ import org.oxycblt.auxio.util.*
* @author Alexander Capehart (OxygenCobalt)
*/
class MainFragment :
ViewBindingFragment<FragmentMainBinding>(), ViewTreeObserver.OnPreDrawListener, NavController.OnDestinationChangedListener {
ViewBindingFragment<FragmentMainBinding>(),
ViewTreeObserver.OnPreDrawListener,
NavController.OnDestinationChangedListener {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val navModel: NavigationViewModel by activityViewModels()
private val selectionModel: SelectionViewModel by activityViewModels()

View file

@ -155,7 +155,7 @@ class DetailViewModel(application: Application) :
} else {
_currentSong.value = null
}
logD("Updated song to ${newSong}")
logD("Updated song to $newSong")
}
val album = currentAlbum.value

View file

@ -105,18 +105,18 @@ private class GenreDetailViewHolder private constructor(private val binding: Ite
* @param genre The new [Song] to bind.
* @param listener A [DetailAdapter.Listener] to bind interactions to.
*/
fun bind(item: Genre, listener: DetailAdapter.Listener) {
binding.detailCover.bind(item)
fun bind(genre: Genre, listener: DetailAdapter.Listener) {
binding.detailCover.bind(genre)
binding.detailType.text = binding.context.getString(R.string.lbl_genre)
binding.detailName.text = item.resolveName(binding.context)
binding.detailName.text = genre.resolveName(binding.context)
// Nothing about a genre is applicable to the sub-head text.
binding.detailSubhead.isVisible = false
// The song count of the genre maps to the info text.
binding.detailInfo.text =
binding.context.getString(
R.string.fmt_two,
binding.context.getPlural(R.plurals.fmt_artist_count, item.artists.size),
binding.context.getPlural(R.plurals.fmt_song_count, item.songs.size))
binding.context.getPlural(R.plurals.fmt_artist_count, genre.artists.size),
binding.context.getPlural(R.plurals.fmt_song_count, genre.songs.size))
binding.detailPlayButton.setOnClickListener { listener.onPlay() }
binding.detailShuffleButton.setOnClickListener { listener.onShuffle() }
}

View file

@ -426,7 +426,7 @@ class HomeFragment :
when (item) {
is Song -> HomeFragmentDirections.actionShowAlbum(item.album.uid)
is Album -> HomeFragmentDirections.actionShowAlbum(item.uid)
is Artist -> HomeFragmentDirections.actionShowArtist(item.uid.also { logD(it) })
is Artist -> HomeFragmentDirections.actionShowArtist(item.uid)
is Genre -> HomeFragmentDirections.actionShowGenre(item.uid)
else -> return
}

View file

@ -175,10 +175,8 @@ object Covers {
* @return An [InputStream] of image data if the cover loading was successful, null otherwise.
*/
@Suppress("BlockingMethodInNonBlockingContext")
private suspend fun fetchMediaStoreCovers(context: Context, data: Album): InputStream? {
val uri = data.coverUri
private suspend fun fetchMediaStoreCovers(context: Context, album: Album): InputStream? {
// Eliminate any chance that this blocking call might mess up the loading process
return withContext(Dispatchers.IO) { context.contentResolver.openInputStream(uri) }
return withContext(Dispatchers.IO) { context.contentResolver.openInputStream(album.coverUri) }
}
}

View file

@ -178,7 +178,7 @@ sealed class Music : Item {
companion object {
/**
* Creates an auxio-style [UID] with a [UUID] composed of a hash of the non-subjective,
* Creates an Auxio-style [UID] with a [UUID] composed of a hash of the non-subjective,
* unlikely-to-change metadata of the music.
* @param mode The analogous [MusicMode] of the item that created this [UID].
* @param updates Block to update the [MessageDigest] hash with the metadata of the
@ -194,7 +194,8 @@ sealed class Music : Item {
}
// Convert the digest to a UUID. This does cleave off some of the hash, but this
// is considered okay.
val uuid = UUID(
val uuid =
UUID(
digest[0]
.toLong()
.shl(56)
@ -224,7 +225,7 @@ sealed class Music : Item {
* @param mode The analogous [MusicMode] of the item that created this [UID].
* @param mbid The analogous MusicBrainz ID for this item that was extracted from a
* file.
* @return A new MusicBrainz-style [UID]
* @return A new MusicBrainz-style [UID].
*/
fun musicBrainz(mode: MusicMode, mbid: UUID): UID = UID(Format.MUSICBRAINZ, mode, mbid)
@ -396,8 +397,7 @@ class Song constructor(raw: Raw, settings: Settings) : Music() {
/**
* Resolves one or more [Artist]s into a single piece of human-readable names.
* @param context [Context] required for [resolveName].
* formatter.
* @param context [Context] required for [resolveName]. formatter.
*/
fun resolveArtistContents(context: Context) =
// TODO Internationalize the list

View file

@ -23,7 +23,6 @@ import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import androidx.core.database.getIntOrNull
import androidx.core.database.getStringOrNull
import androidx.core.database.sqlite.transaction
import java.io.File
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.*
@ -357,23 +356,15 @@ private class CacheDatabase(context: Context) :
put(Columns.ALBUM_SORT_NAME, rawSong.albumSortName)
put(Columns.ALBUM_TYPES, rawSong.albumTypes.toSQLMultiValue())
put(
Columns.ARTIST_MUSIC_BRAINZ_IDS,
rawSong.artistMusicBrainzIds.toSQLMultiValue())
put(Columns.ARTIST_MUSIC_BRAINZ_IDS, rawSong.artistMusicBrainzIds.toSQLMultiValue())
put(Columns.ARTIST_NAMES, rawSong.artistNames.toSQLMultiValue())
put(
Columns.ARTIST_SORT_NAMES,
rawSong.artistSortNames.toSQLMultiValue())
put(Columns.ARTIST_SORT_NAMES, rawSong.artistSortNames.toSQLMultiValue())
put(
Columns.ALBUM_ARTIST_MUSIC_BRAINZ_IDS,
rawSong.albumArtistMusicBrainzIds.toSQLMultiValue())
put(
Columns.ALBUM_ARTIST_NAMES,
rawSong.albumArtistNames.toSQLMultiValue())
put(
Columns.ALBUM_ARTIST_SORT_NAMES,
rawSong.albumArtistSortNames.toSQLMultiValue())
put(Columns.ALBUM_ARTIST_NAMES, rawSong.albumArtistNames.toSQLMultiValue())
put(Columns.ALBUM_ARTIST_SORT_NAMES, rawSong.albumArtistSortNames.toSQLMultiValue())
put(Columns.GENRE_NAMES, rawSong.genreNames.toSQLMultiValue())
}

View file

@ -27,9 +27,8 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.unlikelyToBeNull
/**
* a [ViewModel] that manages the current music picker state.
* Make it so that the dialogs just contain the music themselves and then exit if the library
* changes.
* a [ViewModel] that manages the current music picker state. Make it so that the dialogs just
* contain the music themselves and then exit if the library changes.
* @author Alexander Capehart (OxygenCobalt)
*/
class PickerViewModel : ViewModel(), MusicStore.Callback {

View file

@ -20,7 +20,7 @@ package org.oxycblt.auxio.playback
import org.oxycblt.auxio.IntegerTable
/**
* Represents a configuration option for what kind of "secondary" action to show in a particular
* Represents a configuration option for what kind of "secondary" action to show in a particular UI
* context.
* @author Alexander Capehart (OxygenCobalt)
*/

View file

@ -47,7 +47,10 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
* available controls.
* @author Alexander Capehart (OxygenCobalt)
*/
class PlaybackPanelFragment : ViewBindingFragment<FragmentPlaybackPanelBinding>(), Toolbar.OnMenuItemClickListener, StyledSeekBar.Listener {
class PlaybackPanelFragment :
ViewBindingFragment<FragmentPlaybackPanelBinding>(),
Toolbar.OnMenuItemClickListener,
StyledSeekBar.Listener {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val navModel: NavigationViewModel by activityViewModels()
// AudioEffect expects you to use startActivityForResult with the panel intent. There is no

View file

@ -18,7 +18,6 @@
package org.oxycblt.auxio.playback
import android.text.format.DateUtils
import org.oxycblt.auxio.util.logD
/**
* Convert milliseconds into deci-seconds (1/10th of a second).
@ -58,7 +57,7 @@ fun Long.secsToMs() = times(1000)
fun Long.formatDurationMs(isElapsed: Boolean) = msToSecs().formatDurationSecs(isElapsed)
/**
// * Format a deci-second value (1/10th of a second) into a string duration.
* // * Format a deci-second value (1/10th of a second) into a string duration.
* @param isElapsed Whether this duration is represents elapsed time. If this is false, then --:--
* will be returned if the second value is 0.
*/

View file

@ -152,8 +152,8 @@ class PlaybackViewModel(application: Application) :
/**
* Play a [Song] from one of it's [Artist]s.
* @param song The [Song] to play.
* @param artist The [Artist] to play from. Must be linked to the [Song]. If null, the user
* will be prompted on what artist to play. Defaults to null.
* @param artist The [Artist] to play from. Must be linked to the [Song]. If null, the user will
* be prompted on what artist to play. Defaults to null.
*/
fun playFromArtist(song: Song, artist: Artist? = null) {
if (artist != null) {
@ -234,8 +234,8 @@ class PlaybackViewModel(application: Application) :
}
/**
* Start the given [InternalPlayer.Action] to be completed eventually. This can be used
* to enqueue a playback action at startup to then occur when the music library is fully loaded.
* Start the given [InternalPlayer.Action] to be completed eventually. This can be used to
* enqueue a playback action at startup to then occur when the music library is fully loaded.
* @param action The [InternalPlayer.Action] to perform eventually.
*/
fun startAction(action: InternalPlayer.Action) {

View file

@ -53,7 +53,4 @@ enum class ReplayGainMode {
* @param without The pre-amp (in dB) to use when ReplayGain tags are not present.
* @author Alexander Capehart (OxygenCobalt)
*/
data class ReplayGainPreAmp(
val with: Float,
val without: Float
)
data class ReplayGainPreAmp(val with: Float, val without: Float)

View file

@ -57,8 +57,8 @@ class ReplayGainAudioProcessor(context: Context) : BaseAudioProcessor() {
/**
* Updates the volume adjustment based on the given [Metadata].
* @param metadata The [Metadata] of the currently playing track, or null if the track
* has no [Metadata].
* @param metadata The [Metadata] of the currently playing track, or null if the track has no
* [Metadata].
*/
fun applyReplayGain(metadata: Metadata?) {
// TODO: Allow this to automatically obtain it's own [Metadata].
@ -155,7 +155,8 @@ class ReplayGainAudioProcessor(context: Context) : BaseAudioProcessor() {
// Grok a float from a ReplayGain tag by removing everything that is not 0-9, ,
// or -.
// Derived from vanilla music: https://github.com/vanilla-music/vanilla
val gainValue = try {
val gainValue =
try {
value.replace(Regex("[^\\d.-]"), "").toFloat()
} catch (e: Exception) {
0f
@ -275,8 +276,7 @@ class ReplayGainAudioProcessor(context: Context) : BaseAudioProcessor() {
/**
* A raw ReplayGain adjustment.
* @param key The tag's key.
* @param value The tag's adjustment, in dB.
* TODO: Try to phasse this out.
* @param value The tag's adjustment, in dB. TODO: Try to phasse this out.
*/
private data class GainTag(val key: String, val value: Float)

View file

@ -50,8 +50,8 @@ interface InternalPlayer {
/**
* Get a [State] corresponding to the current player state.
* @param durationMs The duration of the currently playing track, in milliseconds.
* Required since the internal player cannot obtain an accurate duration itself.
* @param durationMs The duration of the currently playing track, in milliseconds. Required
* since the internal player cannot obtain an accurate duration itself.
*/
fun getState(durationMs: Long): State
@ -67,16 +67,14 @@ interface InternalPlayer {
*/
fun setPlaying(isPlaying: Boolean)
/**
* Possible long-running background tasks handled by the background playback task.
*/
/** Possible long-running background tasks handled by the background playback task. */
sealed class Action {
/** Restore the previously saved playback state. */
object RestoreState : Action()
/**
* Start shuffled playback of the entire music library.
* Analogous to the "Shuffle All" shortcut.
* Start shuffled playback of the entire music library. Analogous to the "Shuffle All"
* shortcut.
*/
object ShuffleAll : Action()
@ -100,8 +98,8 @@ interface InternalPlayer {
) {
/**
* Calculate the "real" playback position this instance contains, in milliseconds.
* @return If paused, the original position will be returned. Otherwise, it will be
* the original position plus the time elapsed since this state was created.
* @return If paused, the original position will be returned. Otherwise, it will be the
* original position plus the time elapsed since this state was created.
*/
fun calculateElapsedPositionMs() =
if (isAdvancing) {
@ -154,8 +152,8 @@ interface InternalPlayer {
companion object {
/**
* Create a new instance.
* @param isPlaying Whether the player is actively playing audio or set to play audio
* in the future.
* @param isPlaying Whether the player is actively playing audio or set to play audio in
* the future.
* @param isAdvancing Whether the player is actively playing audio in this moment.
* @param positionMs The current position of the player.
*/

View file

@ -216,8 +216,8 @@ class PlaybackStateDatabase private constructor(context: Context) :
)
/**
* A lower-level form of [SavedState] that contains additional information to create
* a more reliable restoration process.
* A lower-level form of [SavedState] that contains additional information to create a more
* reliable restoration process.
*/
private data class RawState(
/** @see SavedState.index */
@ -229,9 +229,8 @@ class PlaybackStateDatabase private constructor(context: Context) :
/** @see SavedState.isShuffled */
val isShuffled: Boolean,
/**
* The [Music.UID] of the [Song] that was originally in the queue at [index].
* This can be used to restore the currently playing item in the queue if
* the index mapping changed.
* The [Music.UID] of the [Song] that was originally in the queue at [index]. This can be
* used to restore the currently playing item in the queue if the index mapping changed.
*/
val songUid: Music.UID,
/** @see SavedState.parent */

View file

@ -57,6 +57,7 @@ class PlaybackStateManager private constructor() {
private val callbacks = mutableListOf<Callback>()
private var internalPlayer: InternalPlayer? = null
private var pendingAction: InternalPlayer.Action? = null
private var isInitialized = false
/** The currently playing [Song]. Null if nothing is playing. */
val song
@ -84,9 +85,6 @@ class PlaybackStateManager private constructor() {
/** Whether the queue is shuffled. */
var isShuffled = false
private set
/** Whether this instance has played something. */
var isInitialized = false
private set
/**
* The current audio session ID of the internal player. Null if no [InternalPlayer] is
* available.
@ -94,11 +92,9 @@ class PlaybackStateManager private constructor() {
val currentAudioSessionId: Int?
get() = internalPlayer?.audioSessionId
/**
* Add a [Callback] to this instance. This can be used to receive changes in the playback
* state. Will immediately invoke [Callback] methods to initialize the instance with the
* current state.
* Add a [Callback] to this instance. This can be used to receive changes in the playback state.
* Will immediately invoke [Callback] methods to initialize the instance with the current state.
* @param callback The [Callback] to add.
* @see Callback
*/
@ -129,7 +125,8 @@ class PlaybackStateManager private constructor() {
* Register an [InternalPlayer] for this instance. This instance will handle translating the
* current playback state into audio playback. There can be only one [InternalPlayer] at a time.
* Will invoke [InternalPlayer] methods to initialize the instance with the current state.
* @param internalPlayer The [InternalPlayer] to register. Will do nothing if already registered.
* @param internalPlayer The [InternalPlayer] to register. Will do nothing if already
* registered.
*/
@Synchronized
fun registerInternalPlayer(internalPlayer: InternalPlayer) {
@ -201,8 +198,8 @@ class PlaybackStateManager private constructor() {
// --- QUEUE FUNCTIONS ---
/**
* Go to the next [Song] in the queue. Will go to the first [Song] in the queue if there
* is no [Song] ahead to skip to.
* Go to the next [Song] in the queue. Will go to the first [Song] in the queue if there is no
* [Song] ahead to skip to.
*/
@Synchronized
fun next() {
@ -217,8 +214,8 @@ class PlaybackStateManager private constructor() {
}
/**
* Go to the previous [Song] in the queue. Will rewind if there are no previous [Song]s
* to skip to, or if configured to do so.
* Go to the previous [Song] in the queue. Will rewind if there are no previous [Song]s to skip
* to, or if configured to do so.
*/
@Synchronized
fun prev() {
@ -433,9 +430,7 @@ class PlaybackStateManager private constructor() {
internalPlayer?.seekTo(positionMs)
}
/**
* Rewind to the beginning of the currently playing [Song].
*/
/** Rewind to the beginning of the currently playing [Song]. */
fun rewind() = seekTo(0)
// --- PERSISTENCE FUNCTIONS ---
@ -501,14 +496,16 @@ class PlaybackStateManager private constructor() {
logD("Saving state to DB")
// Create the saved state from the current playback state.
val state = synchronized(this) {
val state =
synchronized(this) {
PlaybackStateDatabase.SavedState(
index = index,
parent = parent,
queue = _queue,
positionMs = playerState.calculateElapsedPositionMs(),
isShuffled = isShuffled,
repeatMode = repeatMode) }
repeatMode = repeatMode)
}
return try {
withContext(Dispatchers.IO) { database.write(state) }
true
@ -636,8 +633,8 @@ class PlaybackStateManager private constructor() {
*/
interface Callback {
/**
* Called when the position of the currently playing item has changed, changing the
* current [Song], but no other queue attribute has changed.
* Called when the position of the currently playing item has changed, changing the current
* [Song], but no other queue attribute has changed.
* @param index The new position in the queue.
*/
fun onIndexMoved(index: Int) {}
@ -649,8 +646,8 @@ class PlaybackStateManager private constructor() {
fun onQueueChanged(queue: List<Song>) {}
/**
* Called when the queue has changed in a non-trivial manner (such as re-shuffling),
* but the currently playing [Song] has not.
* Called when the queue has changed in a non-trivial manner (such as re-shuffling), but the
* currently playing [Song] has not.
* @param index The new position in the queue.
*/
fun onQueueReworked(index: Int, queue: List<Song>) {}
@ -659,8 +656,7 @@ class PlaybackStateManager private constructor() {
* Called when a new playback configuration was created.
* @param index The new position in the queue.
* @param queue The new queue.
* @param parent The new [MusicParent] being played from, or null if playing from all
* songs.
* @param parent The new [MusicParent] being played from, or null if playing from all songs.
*/
fun onNewPlayback(index: Int, queue: List<Song>, parent: MusicParent?) {}
@ -677,8 +673,8 @@ class PlaybackStateManager private constructor() {
fun onRepeatChanged(repeatMode: RepeatMode) {}
/**
* Called when the queue's shuffle state changes. Handling the queue change itself
* should occur in [onQueueReworked],
* Called when the queue's shuffle state changes. Handling the queue change itself should
* occur in [onQueueReworked],
* @param isShuffled Whether the queue is shuffled.
*/
fun onShuffledChanged(isShuffled: Boolean) {}

View file

@ -31,8 +31,8 @@ enum class RepeatMode {
NONE,
/**
* Repeat the whole queue. Songs are played immediately, and playback continues when the
* queue repeats.
* Repeat the whole queue. Songs are played immediately, and playback continues when the queue
* repeats.
*/
ALL,

View file

@ -74,8 +74,8 @@ class MediaSessionComponent(private val context: Context, private val callback:
}
/**
* Release this instance, closing the [MediaSessionCompat] and preventing any
* further updates to the [NotificationComponent].
* Release this instance, closing the [MediaSessionCompat] and preventing any further updates to
* the [NotificationComponent].
*/
fun release() {
provider.release()
@ -246,10 +246,10 @@ class MediaSessionComponent(private val context: Context, private val callback:
/**
* Upload a new [MediaMetadataCompat] based on the current playback state to the
* [MediaSessionCompat] and [NotificationComponent].
* @param song The current [Song] to create the [MediaMetadataCompat] from, or null if no
* [Song] is currently playing.
* @param parent The current [MusicParent] to create the [MediaMetadataCompat] from, or null
* if playback is currently occuring from all songs.
* @param song The current [Song] to create the [MediaMetadataCompat] from, or null if no [Song]
* is currently playing.
* @param parent The current [MusicParent] to create the [MediaMetadataCompat] from, or null if
* playback is currently occuring from all songs.
*/
private fun updateMediaMetadata(song: Song?, parent: MusicParent?) {
if (song == null) {
@ -343,7 +343,8 @@ class MediaSessionComponent(private val context: Context, private val callback:
val state =
// InternalPlayer.State handles position/state information.
playbackManager.playerState.intoPlaybackState(PlaybackStateCompat.Builder())
playbackManager.playerState
.intoPlaybackState(PlaybackStateCompat.Builder())
.setActions(ACTIONS)
// Active queue ID corresponds to the indices we populated prior, use them here.
.setActiveQueueItemId(playbackManager.index.toLong())
@ -396,9 +397,7 @@ class MediaSessionComponent(private val context: Context, private val callback:
}
}
/**
* An interface for handling changes in the notification configuration.
*/
/** An interface for handling changes in the notification configuration. */
interface Callback {
/**
* Called when the [NotificationComponent] changes, requiring it to be re-posed.

View file

@ -34,9 +34,8 @@ import org.oxycblt.auxio.util.newBroadcastPendingIntent
import org.oxycblt.auxio.util.newMainPendingIntent
/**
* The playback notification component. Due to race conditions regarding notification
* updates, this component is not self-sufficient. [MediaSessionComponent] should be used
* instead of manage it.
* The playback notification component. Due to race conditions regarding notification updates, this
* component is not self-sufficient. [MediaSessionComponent] should be used instead of manage it.
* @author Alexander Capehart (OxygenCobalt)
*/
@SuppressLint("RestrictedApi")
@ -115,7 +114,8 @@ class NotificationComponent(private val context: Context, sessionToken: MediaSes
context: Context,
isPlaying: Boolean
): NotificationCompat.Action {
val drawableRes = if (isPlaying) {
val drawableRes =
if (isPlaying) {
R.drawable.ic_pause_24
} else {
R.drawable.ic_play_24
@ -134,7 +134,8 @@ class NotificationComponent(private val context: Context, sessionToken: MediaSes
context: Context,
isShuffled: Boolean
): NotificationCompat.Action {
val drawableRes = if (isShuffled) {
val drawableRes =
if (isShuffled) {
R.drawable.ic_shuffle_on_24
} else {
R.drawable.ic_shuffle_off_24
@ -142,13 +143,10 @@ class NotificationComponent(private val context: Context, sessionToken: MediaSes
return buildAction(context, PlaybackService.ACTION_INVERT_SHUFFLE, drawableRes)
}
private fun buildAction(
context: Context,
actionName: String,
@DrawableRes iconRes: Int
) =
private fun buildAction(context: Context, actionName: String, @DrawableRes iconRes: Int) =
NotificationCompat.Action.Builder(
iconRes, actionName, context.newBroadcastPendingIntent(actionName)).build()
iconRes, actionName, context.newBroadcastPendingIntent(actionName))
.build()
companion object {
/** Notification channel used by solely the playback notification. */

View file

@ -141,7 +141,8 @@ class PlaybackService :
.setContentType(C.AUDIO_CONTENT_TYPE_MUSIC)
.build(),
true)
.build().also { it.addListener(this) }
.build()
.also { it.addListener(this) }
// Initialize the core service components
settings = Settings(this, this)
foregroundManager = ForegroundManager(this)
@ -163,8 +164,7 @@ class PlaybackService :
addAction(ACTION_SKIP_NEXT)
addAction(ACTION_EXIT)
addAction(WidgetProvider.ACTION_WIDGET_UPDATE)
}
)
})
logD("Service created")
}
@ -218,7 +218,8 @@ class PlaybackService :
override fun getState(durationMs: Long) =
InternalPlayer.State.new(
player.playWhenReady, player.isPlaying,
player.playWhenReady,
player.isPlaying,
// The position value can be below zero or past the expected duration, make
// sure we handle that.
player.currentPosition.coerceAtLeast(0).coerceAtMost(durationMs))
@ -363,7 +364,8 @@ class PlaybackService :
}
override fun performAction(action: InternalPlayer.Action): Boolean {
val library = musicStore.library
val library =
musicStore.library
// No library, cannot do anything.
?: return false

View file

@ -25,8 +25,7 @@ import android.widget.FrameLayout
/**
* A [FrameLayout] that programmatically overrides the child layout to a left-to-right (LTR) layout
* direction. This is useful for "Timeline" elements that Material Design recommends be LTR in all
* cases. This layout can only contain one child, to prevent conflicts with other layout
* components.
* cases. This layout can only contain one child, to prevent conflicts with other layout components.
* @author Alexander Capehart (OxygenCobalt)
*/
open class ForcedLTRFrameLayout

View file

@ -110,8 +110,8 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
/** A listener for SeekBar interactions. */
interface Listener {
/**
* Called when the internal [Slider] was scrubbed to a new position, requesting that
* a seek be performed.
* Called when the internal [Slider] was scrubbed to a new position, requesting that a seek
* be performed.
* @param positionDs The position to seek to, in deci-seconds (1/10th of a second).
*/
fun onSeekConfirmed(positionDs: Long)

View file

@ -73,7 +73,8 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
* @param recycler [RecyclerView] to expand with, or null if one is currently unavailable.
*/
fun expandWithRecycler(recycler: RecyclerView?) {
// TODO: Is it possible to use liftOnScrollTargetViewId to avoid the [RecyclerView] argument?
// TODO: Is it possible to use liftOnScrollTargetViewId to avoid the [RecyclerView]
// argument?
setExpanded(true)
recycler?.let { addOnOffsetChangedListener(ExpansionHackListener(it)) }
}

View file

@ -1,3 +1,20 @@
/*
* Copyright (c) 2022 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.util
import android.content.ContentValues
@ -5,7 +22,6 @@ import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import androidx.core.database.sqlite.transaction
/**
* Query all columns in the given [SQLiteDatabase] table, running the block when the [Cursor] is
* loaded. The block will be called with [use], allowing for automatic cleanup of [Cursor]
@ -22,22 +38,23 @@ inline fun <R> SQLiteDatabase.queryAll(tableName: String, block: (Cursor) -> R)
* @param schema A block that adds a comma-separated list of SQL column declarations.
*/
inline fun SQLiteDatabase.createTable(name: String, schema: StringBuilder.() -> StringBuilder) {
val command = StringBuilder()
.append("CREATE TABLE IF NOT EXISTS $name(")
.schema()
.append(")")
val command = StringBuilder().append("CREATE TABLE IF NOT EXISTS $name(").schema().append(")")
execSQL(command.toString())
}
/**
* Safely write a list of items to an [SQLiteDatabase]. This will clear the prior list and write
* as much of the new list as possible.
* Safely write a list of items to an [SQLiteDatabase]. This will clear the prior list and write as
* much of the new list as possible.
* @param list The list of items to write.
* @param tableName The name of the table to write the items to.
* @param transform Code to transform an item into a corresponding [ContentValues] to the given
* table.
*/
inline fun <reified T> SQLiteDatabase.writeList(list: List<T>, tableName: String, transform: (Int, T) -> ContentValues) {
inline fun <reified T> SQLiteDatabase.writeList(
list: List<T>,
tableName: String,
transform: (Int, T) -> ContentValues
) {
// Clear any prior items in the table.
transaction { delete(tableName, null, null) }
@ -50,14 +67,15 @@ inline fun <reified T> SQLiteDatabase.writeList(list: List<T>, tableName: String
transaction {
while (i < list.size) {
val values = transform(i, list[i])
// Increment forward now so that if this insert fails, the transactionPosition
// Increment forward now so that if this insert fails, the transaction position
// will still start at the next i.
i++
insert(tableName, null, values)
}
}
transactionPosition = i
logD("Wrote batch of ${T::class.simpleName} instances. " +
logD(
"Wrote batch of ${T::class.simpleName} instances. " +
"Position is now at $transactionPosition")
}
}

View file

@ -17,10 +17,7 @@
package org.oxycblt.auxio.util
import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.graphics.PointF
import android.graphics.drawable.Drawable
import android.os.Build
@ -30,7 +27,6 @@ import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.database.sqlite.transaction
import androidx.core.graphics.Insets
import androidx.core.graphics.drawable.DrawableCompat
import androidx.fragment.app.Fragment

View file

@ -65,7 +65,7 @@ fun lazyReflectedField(clazz: KClass<*>, field: String) = lazy {
* Lazily set up a reflected method. Automatically handles visibility changes. Adapted from Material
* Files: https://github.com/zhanghai/MaterialFiles
* @param clazz The [KClass] to reflect into.
* @param field The name of the method to obtain.
* @param method The name of the method to obtain.
*/
fun lazyReflectedMethod(clazz: KClass<*>, method: String) = lazy {
clazz.java.getDeclaredMethod(method).also { it.isAccessible = true }

View file

@ -217,9 +217,9 @@ class WidgetProvider : AppWidgetProvider() {
// widgets.
val background =
if (Settings(context).roundMode && Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
R.drawable.ui_widget_bar_round
R.drawable.ui_widget_bg_round
} else {
R.drawable.ui_widget_bar_system
R.drawable.ui_widget_bg_system
}
setBackgroundResource(android.R.id.background, background)
return this

View file

@ -80,7 +80,7 @@ fun RemoteViews.setLayoutDirection(@IdRes viewId: Int, layoutDirection: Int) {
}
/**
* Update the app widget layouts corresponding to the given [AppWidgetProvider] [ComponentName] with
* Update the app widget layouts corresponding to the given [WidgetProvider] [ComponentName] with
* an adaptive layout, in a version-compatible manner.
* @param context [Context] required to backport adaptive layout behavior.
* @param component [ComponentName] of the app widget layout to update.

View file

@ -129,12 +129,10 @@
<string name="fmt_lib_song_count">Canciones cargadas: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d canción</item>
<item quantity="many">%d canciones</item>
<item quantity="other">%d canciones</item>
</plurals>
<plurals name="fmt_album_count">
<item quantity="one">%d álbum</item>
<item quantity="many">%d álbumes</item>
<item quantity="other">%d álbumes</item>
</plurals>
<string name="lbl_size">Tamaño</string>

View file

@ -136,12 +136,10 @@
<string name="fmt_lib_total_duration">Durata totale: %s</string>
<plurals name="fmt_song_count">
<item quantity="one">%d canzone</item>
<item quantity="many">%d canzoni</item>
<item quantity="other">%d canzoni</item>
</plurals>
<plurals name="fmt_album_count">
<item quantity="one">%d disco</item>
<item quantity="many">%d dischi</item>
<item quantity="other">%d dischi</item>
</plurals>
<string name="set_dirs_mode">Modo</string>
@ -252,7 +250,6 @@
<string name="set_separators_plus">Più (+)</string>
<plurals name="fmt_artist_count">
<item quantity="one">%d artista</item>
<item quantity="many">%d artisti</item>
<item quantity="other">%d artisti</item>
</plurals>
<string name="set_rescan">Riscansiona musica</string>

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources />

View file

@ -63,12 +63,10 @@
<string name="fmt_lib_song_count">Músicas carregadas: %d</string>
<plurals name="fmt_song_count">
<item quantity="one">%d música</item>
<item quantity="many">%d músicas</item>
<item quantity="other">%d músicas</item>
</plurals>
<plurals name="fmt_album_count">
<item quantity="one">%d álbum</item>
<item quantity="many">%d álbuns</item>
<item quantity="other">%d álbuns</item>
</plurals>
<string name="lbl_sort_asc">Crescente</string>

View file

@ -5,6 +5,7 @@
<style name="Widget.Auxio.AppBarLayout" parent="Widget.Material3.AppBarLayout">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<!-- Resolve lifted state flickering when scrolling fast. -->
<item name="android:stateListAnimator">@null</item>
</style>