musikr: remove trivial auxio dependence

There's still some thorny resource use left over, but this is a good
starting point to start breaking off musikr from auxio.
This commit is contained in:
Alexander Capehart 2024-12-13 20:08:58 -07:00
parent 3da9e6c5b3
commit de1c091517
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
39 changed files with 324 additions and 203 deletions

View file

@ -31,6 +31,7 @@ import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.list.menu.Menu
import org.oxycblt.auxio.music.PlaylistDecision import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.PlaylistMessage import org.oxycblt.auxio.music.PlaylistMessage
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.PlaybackDecision import org.oxycblt.auxio.playback.PlaybackDecision
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collect
@ -43,7 +44,6 @@ import org.oxycblt.musikr.Album
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
import org.oxycblt.musikr.MusicParent import org.oxycblt.musikr.MusicParent
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -31,6 +31,7 @@ import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.menu.Menu import org.oxycblt.auxio.list.menu.Menu
import org.oxycblt.auxio.music.PlaylistDecision import org.oxycblt.auxio.music.PlaylistDecision
import org.oxycblt.auxio.music.PlaylistMessage import org.oxycblt.auxio.music.PlaylistMessage
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.PlaybackDecision import org.oxycblt.auxio.playback.PlaybackDecision
import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
@ -43,7 +44,6 @@ import org.oxycblt.musikr.Artist
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
import org.oxycblt.musikr.MusicParent import org.oxycblt.musikr.MusicParent
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -32,6 +32,7 @@ import org.oxycblt.auxio.databinding.DialogSongDetailBinding
import org.oxycblt.auxio.detail.list.SongProperty import org.oxycblt.auxio.detail.list.SongProperty
import org.oxycblt.auxio.detail.list.SongPropertyAdapter import org.oxycblt.auxio.detail.list.SongPropertyAdapter
import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.replaygain.formatDb import org.oxycblt.auxio.playback.replaygain.formatDb
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
@ -40,7 +41,6 @@ import org.oxycblt.auxio.util.concatLocalized
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.metadata.AudioProperties import org.oxycblt.musikr.metadata.AudioProperties
import org.oxycblt.musikr.resolveNames
import org.oxycblt.musikr.tag.Name import org.oxycblt.musikr.tag.Name
import timber.log.Timber as L import timber.log.Timber as L

View file

@ -40,12 +40,12 @@ import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.list.recycler.MaterialDragCallback import org.oxycblt.auxio.list.recycler.MaterialDragCallback
import org.oxycblt.auxio.list.recycler.SongViewHolder import org.oxycblt.auxio.list.recycler.SongViewHolder
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getAttrColorCompat import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.inflater import org.oxycblt.auxio.util.inflater
import org.oxycblt.musikr.Playlist import org.oxycblt.musikr.Playlist
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -23,7 +23,6 @@ import android.view.ViewGroup
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemSongPropertyBinding import org.oxycblt.auxio.databinding.ItemSongPropertyBinding
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.list.recycler.DialogRecyclerView import org.oxycblt.auxio.list.recycler.DialogRecyclerView
@ -53,7 +52,7 @@ class SongPropertyAdapter :
* @param value The value of the property. * @param value The value of the property.
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
data class SongProperty(@StringRes val name: Int, val value: String) : Item data class SongProperty(@StringRes val name: Int, val value: String)
/** /**
* A [RecyclerView.ViewHolder] that displays a [SongProperty]. Use [from] to create an instance. * A [RecyclerView.ViewHolder] that displays a [SongProperty]. Use [from] to create an instance.

View file

@ -22,9 +22,9 @@ import androidx.annotation.StringRes
// TODO: Consider breaking this up into sealed classes for individual adapters // TODO: Consider breaking this up into sealed classes for individual adapters
/** A marker for something that is a RecyclerView item. Has no functionality on it's own. */ /** A marker for something that is a RecyclerView item. Has no functionality on it's own. */
interface Item typealias Item = Any
interface Header : Item interface Header
/** /**
* A "header" used for delimiting groups of data. * A "header" used for delimiting groups of data.
@ -44,7 +44,7 @@ interface PlainHeader : Header {
*/ */
data class BasicHeader(@StringRes override val titleRes: Int) : PlainHeader data class BasicHeader(@StringRes override val titleRes: Int) : PlainHeader
interface Divider<T> : Item { interface Divider<T> {
val anchor: T? val anchor: T?
} }

View file

@ -28,6 +28,7 @@ import org.oxycblt.auxio.databinding.DialogMenuBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.ListViewModel
import org.oxycblt.auxio.music.MusicViewModel import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.util.getPlural import org.oxycblt.auxio.util.getPlural
@ -37,7 +38,6 @@ import org.oxycblt.musikr.Artist
import org.oxycblt.musikr.Genre import org.oxycblt.musikr.Genre
import org.oxycblt.musikr.Playlist import org.oxycblt.musikr.Playlist
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
/** /**
* [MenuDialogFragment] implementation for a [Song]. * [MenuDialogFragment] implementation for a [Song].

View file

@ -32,6 +32,8 @@ import org.oxycblt.auxio.list.PlainDivider
import org.oxycblt.auxio.list.SelectableListListener import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.music.areNamesTheSame
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getPlural import org.oxycblt.auxio.util.getPlural
import org.oxycblt.auxio.util.inflater import org.oxycblt.auxio.util.inflater
@ -40,8 +42,6 @@ import org.oxycblt.musikr.Artist
import org.oxycblt.musikr.Genre import org.oxycblt.musikr.Genre
import org.oxycblt.musikr.Playlist import org.oxycblt.musikr.Playlist
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.areNamesTheSame
import org.oxycblt.musikr.resolveNames
/** /**
* A [RecyclerView.ViewHolder] that displays a [Song]. Use [from] to create an instance. * A [RecyclerView.ViewHolder] that displays a [Song]. Use [from] to create an instance.

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2024 Auxio Project
* MusicUtil.kt is part of Auxio.
*
* 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.music
import android.content.Context
import kotlin.math.max
import org.oxycblt.auxio.util.concatLocalized
import org.oxycblt.musikr.Music
/**
* Run [Name.resolve] on each instance in the given list and concatenate them into a [String] in a
* localized manner.
*
* @param context [Context] required
* @return A concatenated string.
*/
fun <T : Music> List<T>.resolveNames(context: Context) =
concatLocalized(context) { it.name.resolve(context) }
/**
* Returns if [Music.name] matches for each item in a list. Useful for scenarios where the display
* information of an item must be compared without a context.
*
* @param other The list of items to compare to.
* @return True if they are the same (by [Music.name]), false otherwise.
*/
fun <T : Music> List<T>.areNamesTheSame(other: List<T>): Boolean {
for (i in 0 until max(size, other.size)) {
val a = getOrNull(i) ?: return false
val b = other.getOrNull(i) ?: return false
if (a.name != b.name) {
return false
}
}
return true
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2024 Auxio Project
* ReplayGainPreAmp.kt is part of Auxio.
*
* 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.music
/**
* The current ReplayGain pre-amp configuration.
*
* @param with The pre-amp (in dB) to use when ReplayGain tags are present.
* @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)

View file

@ -25,7 +25,6 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.sort.Sort import org.oxycblt.auxio.list.sort.Sort
import org.oxycblt.auxio.music.MusicRepository import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.PlaylistDecision import org.oxycblt.auxio.music.PlaylistDecision
@ -354,4 +353,4 @@ sealed interface ChosenName {
* [Playlist]. * [Playlist].
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
data class PlaylistChoice(val playlist: Playlist, val alreadyAdded: Boolean) : Item data class PlaylistChoice(val playlist: Playlist, val alreadyAdded: Boolean)

View file

@ -27,6 +27,7 @@ import androidx.annotation.StringRes
import androidx.media.utils.MediaConstants import androidx.media.utils.MediaConstants
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.formatDurationDs import org.oxycblt.auxio.playback.formatDurationDs
import org.oxycblt.auxio.util.getPlural import org.oxycblt.auxio.util.getPlural
import org.oxycblt.musikr.Album import org.oxycblt.musikr.Album
@ -36,7 +37,6 @@ import org.oxycblt.musikr.Music
import org.oxycblt.musikr.MusicParent import org.oxycblt.musikr.MusicParent
import org.oxycblt.musikr.Playlist import org.oxycblt.musikr.Playlist
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
sealed interface MediaSessionUID { sealed interface MediaSessionUID {
data class Tab(val node: TabNode) : MediaSessionUID { data class Tab(val node: TabNode) : MediaSessionUID {

View file

@ -26,13 +26,13 @@ import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.ui.ViewBindingFragment import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.getAttrColorCompat import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.getColorCompat import org.oxycblt.auxio.util.getColorCompat
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -35,6 +35,7 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding import org.oxycblt.auxio.databinding.FragmentPlaybackPanelBinding
import org.oxycblt.auxio.detail.DetailViewModel import org.oxycblt.auxio.detail.DetailViewModel
import org.oxycblt.auxio.list.ListViewModel import org.oxycblt.auxio.list.ListViewModel
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.playback.ui.StyledSeekBar import org.oxycblt.auxio.playback.ui.StyledSeekBar
import org.oxycblt.auxio.playback.ui.SwipeCoverView import org.oxycblt.auxio.playback.ui.SwipeCoverView
@ -44,7 +45,6 @@ import org.oxycblt.auxio.util.showToast
import org.oxycblt.auxio.util.systemBarInsetsCompat import org.oxycblt.auxio.util.systemBarInsetsCompat
import org.oxycblt.musikr.MusicParent import org.oxycblt.musikr.MusicParent
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -24,8 +24,8 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.ReplayGainPreAmp
import org.oxycblt.auxio.playback.replaygain.ReplayGainMode import org.oxycblt.auxio.playback.replaygain.ReplayGainMode
import org.oxycblt.auxio.playback.replaygain.ReplayGainPreAmp
import org.oxycblt.auxio.settings.Settings import org.oxycblt.auxio.settings.Settings
import timber.log.Timber as L import timber.log.Timber as L

View file

@ -32,11 +32,11 @@ import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
import org.oxycblt.auxio.list.adapter.PlayingIndicatorAdapter import org.oxycblt.auxio.list.adapter.PlayingIndicatorAdapter
import org.oxycblt.auxio.list.recycler.MaterialDragCallback import org.oxycblt.auxio.list.recycler.MaterialDragCallback
import org.oxycblt.auxio.list.recycler.SongViewHolder import org.oxycblt.auxio.list.recycler.SongViewHolder
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.util.context import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getAttrColorCompat import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.inflater import org.oxycblt.auxio.util.inflater
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -26,6 +26,7 @@ import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.DialogPreAmpBinding import org.oxycblt.auxio.databinding.DialogPreAmpBinding
import org.oxycblt.auxio.music.ReplayGainPreAmp
import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
import timber.log.Timber as L import timber.log.Timber as L

View file

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2022 Auxio Project * Copyright (c) 2024 Auxio Project
* ReplayGain.kt is part of Auxio. * ReplayGainMode.kt is part of Auxio.
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -18,10 +18,7 @@
package org.oxycblt.auxio.playback.replaygain package org.oxycblt.auxio.playback.replaygain
import android.content.Context
import kotlin.math.abs
import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
/** /**
* The current ReplayGain configuration. * The current ReplayGain configuration.
@ -55,34 +52,3 @@ enum class ReplayGainMode {
} }
} }
} }
/**
* Represents a ReplayGain adjustment to apply during song playback.
*
* @param track The track-specific adjustment that should be applied. Null if not available.
* @param album A more general album-specific adjustment that should be applied. Null if not
* available.
*/
data class ReplayGainAdjustment(val track: Float?, val album: Float?)
/**
* The current ReplayGain pre-amp configuration.
*
* @param with The pre-amp (in dB) to use when ReplayGain tags are present.
* @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)
/**
* Format a decibel value in a human-readable format.
*
* @param context The context to resolve resources from.
* @return A formatted decibel value. Will be prefixed by a + or - sign.
*/
fun Float.formatDb(context: Context) =
if (this >= 0) {
context.getString(R.string.fmt_db_pos, this)
} else {
context.getString(R.string.fmt_db_neg, abs(this))
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2024 Auxio Project
* ReplayGainUtil.kt is part of Auxio.
*
* 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.playback.replaygain
import android.content.Context
import kotlin.math.abs
import org.oxycblt.auxio.R
/**
* Format a decibel value in a human-readable format.
*
* @param context The context to resolve resources from.
* @return A formatted decibel value. Will be prefixed by a + or - sign.
*/
fun Float.formatDb(context: Context) =
if (this >= 0) {
context.getString(R.string.fmt_db_pos, this)
} else {
context.getString(R.string.fmt_db_neg, abs(this))
}

View file

@ -36,6 +36,7 @@ import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.BitmapProvider import org.oxycblt.auxio.image.BitmapProvider
import org.oxycblt.auxio.image.ImageSettings import org.oxycblt.auxio.image.ImageSettings
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.music.service.MediaSessionUID import org.oxycblt.auxio.music.service.MediaSessionUID
import org.oxycblt.auxio.music.service.toMediaDescription import org.oxycblt.auxio.music.service.toMediaDescription
import org.oxycblt.auxio.playback.ActionMode import org.oxycblt.auxio.playback.ActionMode
@ -48,7 +49,6 @@ import org.oxycblt.auxio.util.newBroadcastPendingIntent
import org.oxycblt.auxio.util.newMainPendingIntent import org.oxycblt.auxio.util.newMainPendingIntent
import org.oxycblt.musikr.MusicParent import org.oxycblt.musikr.MusicParent
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -18,11 +18,8 @@
package org.oxycblt.auxio.util package org.oxycblt.auxio.util
import java.security.MessageDigest
import java.util.UUID
import kotlin.reflect.KClass import kotlin.reflect.KClass
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.musikr.tag.Date
/** /**
* Sanitizes a value that is unlikely to be null. On debug builds, this aliases to [requireNotNull], * Sanitizes a value that is unlikely to be null. On debug builds, this aliases to [requireNotNull],
@ -43,28 +40,6 @@ fun <T> unlikelyToBeNull(value: T?) =
*/ */
fun Int.positiveOrNull() = if (this > 0) this else null fun Int.positiveOrNull() = if (this > 0) this else null
/**
* Aliases a check to ensure that the given number is non-zero.
*
* @return The same number if it's non-zero, null otherwise.
*/
fun Long.positiveOrNull() = if (this > 0) this else null
/**
* Aliases a check to ensure that the given number is non-zero.
*
* @return The same number if it's non-zero, null otherwise.
*/
fun Float.nonZeroOrNull() = if (this != 0f) this else null
/**
* Aliases a check to ensure a given value is in a specified range.
*
* @param range The valid range of values for this number.
* @return The same number if it is in the range, null otherwise.
*/
fun Int.inRangeOrNull(range: IntRange) = if (range.contains(this)) this else null
/** /**
* Lazily set up a reflected field. Automatically handles visibility changes. Adapted from Material * Lazily set up a reflected field. Automatically handles visibility changes. Adapted from Material
* Files: https://github.com/zhanghai/MaterialFiles * Files: https://github.com/zhanghai/MaterialFiles
@ -75,6 +50,7 @@ fun Int.inRangeOrNull(range: IntRange) = if (range.contains(this)) this else nul
fun lazyReflectedField(clazz: KClass<*>, field: String) = lazy { fun lazyReflectedField(clazz: KClass<*>, field: String) = lazy {
clazz.java.getDeclaredField(field).also { it.isAccessible = true } clazz.java.getDeclaredField(field).also { it.isAccessible = true }
} }
/** /**
* Lazily set up a reflected method. Automatically handles visibility changes. Adapted from Material * Lazily set up a reflected method. Automatically handles visibility changes. Adapted from Material
* Files: https://github.com/zhanghai/MaterialFiles * Files: https://github.com/zhanghai/MaterialFiles
@ -87,64 +63,3 @@ fun lazyReflectedMethod(clazz: KClass<*>, method: String, vararg params: KClass<
it.isAccessible = true it.isAccessible = true
} }
} }
/**
* Convert a [String] to a [UUID].
*
* @return A [UUID] converted from the [String] value, or null if the value was not valid.
* @see UUID.fromString
*/
fun String.toUuidOrNull(): UUID? =
try {
UUID.fromString(this)
} catch (e: IllegalArgumentException) {
null
}
/**
* Update a [MessageDigest] with a lowercase [String].
*
* @param string The [String] to hash. If null, it will not be hashed.
*/
fun MessageDigest.update(string: String?) {
if (string != null) {
update(string.lowercase().toByteArray())
} else {
update(0)
}
}
/**
* Update a [MessageDigest] with the string representation of a [Date].
*
* @param date The [Date] to hash. If null, nothing will be done.
*/
fun MessageDigest.update(date: Date?) {
if (date != null) {
update(date.toString().toByteArray())
} else {
update(0)
}
}
/**
* Update a [MessageDigest] with the lowercase versions of all of the input [String]s.
*
* @param strings The [String]s to hash. If a [String] is null, it will not be hashed.
*/
fun MessageDigest.update(strings: List<String?>) {
strings.forEach(::update)
}
/**
* Update a [MessageDigest] with the little-endian bytes of a [Int].
*
* @param n The [Int] to write. If null, nothing will be done.
*/
fun MessageDigest.update(n: Int?) {
if (n != null) {
update(byteArrayOf(n.toByte(), n.shr(8).toByte(), n.shr(16).toByte(), n.shr(24).toByte()))
} else {
update(0)
}
}

View file

@ -30,12 +30,12 @@ import android.view.View
import android.widget.RemoteViews import android.widget.RemoteViews
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.service.PlaybackActions import org.oxycblt.auxio.playback.service.PlaybackActions
import org.oxycblt.auxio.playback.state.RepeatMode import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.ui.UISettings import org.oxycblt.auxio.ui.UISettings
import org.oxycblt.auxio.ui.UISettingsImpl import org.oxycblt.auxio.ui.UISettingsImpl
import org.oxycblt.auxio.util.newBroadcastPendingIntent import org.oxycblt.auxio.util.newBroadcastPendingIntent
import org.oxycblt.musikr.resolveNames
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -18,20 +18,13 @@
package org.oxycblt.musikr package org.oxycblt.musikr
import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Parcelable import android.os.Parcelable
import androidx.room.TypeConverter import androidx.room.TypeConverter
import java.security.MessageDigest import java.security.MessageDigest
import java.util.UUID import java.util.UUID
import kotlin.math.max
import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
import org.oxycblt.auxio.util.concatLocalized
import org.oxycblt.auxio.util.toUuidOrNull
import org.oxycblt.musikr.cover.Cover import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.fs.Format import org.oxycblt.musikr.fs.Format
import org.oxycblt.musikr.fs.Path import org.oxycblt.musikr.fs.Path
@ -39,6 +32,8 @@ import org.oxycblt.musikr.tag.Date
import org.oxycblt.musikr.tag.Disc import org.oxycblt.musikr.tag.Disc
import org.oxycblt.musikr.tag.Name import org.oxycblt.musikr.tag.Name
import org.oxycblt.musikr.tag.ReleaseType import org.oxycblt.musikr.tag.ReleaseType
import org.oxycblt.musikr.tag.ReplayGainAdjustment
import org.oxycblt.musikr.util.toUuidOrNull
/** /**
* Abstract music data. This contains universal information about all concrete music * Abstract music data. This contains universal information about all concrete music
@ -46,7 +41,7 @@ import org.oxycblt.musikr.tag.ReleaseType
* *
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
sealed interface Music : Item { sealed interface Music {
/** /**
* A unique identifier for this music item. * A unique identifier for this music item.
* *
@ -189,7 +184,7 @@ sealed interface Music : Item {
* Creates a MusicBrainz-style [UID] with a [UUID] derived from the MusicBrainz ID * Creates a MusicBrainz-style [UID] with a [UUID] derived from the MusicBrainz ID
* extracted from a file. * extracted from a file.
* *
* @param item The analogous [MusicType] of the item that created this [UID]. * @param item The [Item] that created this [UID].
* @param mbid The analogous MusicBrainz ID for this item that was extracted from a * @param mbid The analogous MusicBrainz ID for this item that was extracted from a
* file. * file.
* @return A new MusicBrainz-style [UID]. * @return A new MusicBrainz-style [UID].
@ -372,32 +367,3 @@ interface Playlist : MusicParent {
/** Useful information to quickly obtain a (single) cover for a Genre. */ /** Useful information to quickly obtain a (single) cover for a Genre. */
val cover: Cover val cover: Cover
} }
/**
* Run [Name.resolve] on each instance in the given list and concatenate them into a [String] in a
* localized manner.
*
* @param context [Context] required
* @return A concatenated string.
*/
fun <T : Music> List<T>.resolveNames(context: Context) =
concatLocalized(context) { it.name.resolve(context) }
/**
* Returns if [Music.name] matches for each item in a list. Useful for scenarios where the display
* information of an item must be compared without a context.
*
* @param other The list of items to compare to.
* @return True if they are the same (by [Music.name]), false otherwise.
*/
fun <T : Music> List<T>.areNamesTheSame(other: List<T>): Boolean {
for (i in 0 until max(size, other.size)) {
val a = getOrNull(i) ?: return false
val b = other.getOrNull(i) ?: return false
if (a.name != b.name) {
return false
}
}
return true
}

View file

@ -18,7 +18,6 @@
package org.oxycblt.musikr.cover package org.oxycblt.musikr.cover
import org.oxycblt.auxio.list.sort.Sort
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
sealed interface Cover { sealed interface Cover {
@ -31,8 +30,6 @@ sealed interface Cover {
} }
companion object { companion object {
private val FALLBACK_SORT = Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING)
fun nil() = Multi(listOf()) fun nil() = Multi(listOf())
fun single(key: String) = Single(key) fun single(key: String) = Single(key)
@ -40,10 +37,11 @@ sealed interface Cover {
fun multi(songs: Collection<Song>) = order(songs).run { Multi(this) } fun multi(songs: Collection<Song>) = order(songs).run { Multi(this) }
private fun order(songs: Collection<Song>) = private fun order(songs: Collection<Song>) =
FALLBACK_SORT.songs(songs) songs
.mapNotNull { it.cover } .mapNotNull { it.cover }
.groupBy { it.key } .groupBy { it.key }
.entries .entries
.sortedByDescending { it.key }
.sortedByDescending { it.value.size } .sortedByDescending { it.value.size }
.map { it.value.first() } .map { it.value.first() }
} }

View file

@ -19,7 +19,7 @@
package org.oxycblt.musikr.fs package org.oxycblt.musikr.fs
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import org.oxycblt.auxio.util.unlikelyToBeNull import org.oxycblt.musikr.util.unlikelyToBeNull
sealed interface Format { sealed interface Format {
val mimeType: String val mimeType: String

View file

@ -18,12 +18,12 @@
package org.oxycblt.musikr.graph package org.oxycblt.musikr.graph
import org.oxycblt.auxio.util.unlikelyToBeNull
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
import org.oxycblt.musikr.tag.interpret.PreAlbum import org.oxycblt.musikr.tag.interpret.PreAlbum
import org.oxycblt.musikr.tag.interpret.PreArtist import org.oxycblt.musikr.tag.interpret.PreArtist
import org.oxycblt.musikr.tag.interpret.PreGenre import org.oxycblt.musikr.tag.interpret.PreGenre
import org.oxycblt.musikr.tag.interpret.PreSong import org.oxycblt.musikr.tag.interpret.PreSong
import org.oxycblt.musikr.util.unlikelyToBeNull
import timber.log.Timber as L import timber.log.Timber as L
data class MusicGraph( data class MusicGraph(

View file

@ -21,11 +21,11 @@ package org.oxycblt.musikr.metadata
import android.content.Context import android.content.Context
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.oxycblt.auxio.util.unlikelyToBeNull
import org.oxycblt.ktaglib.FileRef import org.oxycblt.ktaglib.FileRef
import org.oxycblt.ktaglib.KTagLib import org.oxycblt.ktaglib.KTagLib
import org.oxycblt.ktaglib.Metadata import org.oxycblt.ktaglib.Metadata
import org.oxycblt.musikr.fs.query.DeviceFile import org.oxycblt.musikr.fs.query.DeviceFile
import org.oxycblt.musikr.util.unlikelyToBeNull
interface MetadataExtractor { interface MetadataExtractor {
suspend fun extract(file: DeviceFile): Metadata? suspend fun extract(file: DeviceFile): Metadata?

View file

@ -18,7 +18,6 @@
package org.oxycblt.musikr.model package org.oxycblt.musikr.model
import org.oxycblt.auxio.util.update
import org.oxycblt.musikr.Album import org.oxycblt.musikr.Album
import org.oxycblt.musikr.Artist import org.oxycblt.musikr.Artist
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
@ -26,6 +25,7 @@ import org.oxycblt.musikr.Song
import org.oxycblt.musikr.cover.Cover import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.tag.Date import org.oxycblt.musikr.tag.Date
import org.oxycblt.musikr.tag.interpret.PreAlbum import org.oxycblt.musikr.tag.interpret.PreAlbum
import org.oxycblt.musikr.util.update
interface AlbumCore { interface AlbumCore {
val preAlbum: PreAlbum val preAlbum: PreAlbum

View file

@ -18,7 +18,6 @@
package org.oxycblt.musikr.model package org.oxycblt.musikr.model
import org.oxycblt.auxio.util.update
import org.oxycblt.musikr.Album import org.oxycblt.musikr.Album
import org.oxycblt.musikr.Artist import org.oxycblt.musikr.Artist
import org.oxycblt.musikr.Genre import org.oxycblt.musikr.Genre
@ -26,6 +25,7 @@ import org.oxycblt.musikr.Music
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.cover.Cover import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.tag.interpret.PreArtist import org.oxycblt.musikr.tag.interpret.PreArtist
import org.oxycblt.musikr.util.update
interface ArtistCore { interface ArtistCore {
val preArtist: PreArtist val preArtist: PreArtist

View file

@ -18,13 +18,13 @@
package org.oxycblt.musikr.model package org.oxycblt.musikr.model
import org.oxycblt.auxio.util.update
import org.oxycblt.musikr.Artist import org.oxycblt.musikr.Artist
import org.oxycblt.musikr.Genre import org.oxycblt.musikr.Genre
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.cover.Cover import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.tag.interpret.PreGenre import org.oxycblt.musikr.tag.interpret.PreGenre
import org.oxycblt.musikr.util.update
interface GenreCore { interface GenreCore {
val preGenre: PreGenre val preGenre: PreGenre

View file

@ -25,7 +25,7 @@ import java.io.BufferedWriter
import java.io.InputStream import java.io.InputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.io.OutputStream import java.io.OutputStream
import org.oxycblt.auxio.util.unlikelyToBeNull import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.musikr.Playlist import org.oxycblt.musikr.Playlist
import org.oxycblt.musikr.fs.Components import org.oxycblt.musikr.fs.Components
import org.oxycblt.musikr.fs.Path import org.oxycblt.musikr.fs.Path
@ -34,8 +34,8 @@ import org.oxycblt.musikr.fs.path.VolumeManager
import org.oxycblt.musikr.playlist.ExportConfig import org.oxycblt.musikr.playlist.ExportConfig
import org.oxycblt.musikr.playlist.ImportedPlaylist import org.oxycblt.musikr.playlist.ImportedPlaylist
import org.oxycblt.musikr.playlist.PossiblePaths import org.oxycblt.musikr.playlist.PossiblePaths
import org.oxycblt.musikr.resolveNames
import org.oxycblt.musikr.tag.util.correctWhitespace import org.oxycblt.musikr.tag.util.correctWhitespace
import org.oxycblt.musikr.util.unlikelyToBeNull
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -23,8 +23,8 @@ import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import kotlin.math.max import kotlin.math.max
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.inRangeOrNull import org.oxycblt.musikr.util.inRangeOrNull
import org.oxycblt.auxio.util.positiveOrNull import org.oxycblt.musikr.util.positiveOrNull
import timber.log.Timber as L import timber.log.Timber as L
/** /**

View file

@ -20,7 +20,6 @@ package org.oxycblt.musikr.tag
import android.content.Context import android.content.Context
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.Item
/** /**
* A disc identifier for a song. * A disc identifier for a song.
@ -28,7 +27,7 @@ import org.oxycblt.auxio.list.Item
* @param number The disc number. * @param number The disc number.
* @param name The name of the disc group, if any. Null if not present. * @param name The name of the disc group, if any. Null if not present.
*/ */
class Disc(val number: Int, val name: String?) : Item, Comparable<Disc> { class Disc(val number: Int, val name: String?) : Comparable<Disc> {
// We don't want to group discs by differing subtitles, so only compare by the number // We don't want to group discs by differing subtitles, so only compare by the number
override fun equals(other: Any?) = other is Disc && number == other.number override fun equals(other: Any?) = other is Disc && number == other.number

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 Auxio Project
* ReplayGainAdjustment.kt is part of Auxio.
*
* 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.musikr.tag
/**
* Represents a ReplayGain adjustment to apply during song playback.
*
* @param track The track-specific adjustment that should be applied. Null if not available.
* @param album A more general album-specific adjustment that should be applied. Null if not
* available.
*/
data class ReplayGainAdjustment(val track: Float?, val album: Float?)

View file

@ -20,8 +20,6 @@ package org.oxycblt.musikr.tag.interpret
import android.net.Uri import android.net.Uri
import java.util.UUID import java.util.UUID
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
import org.oxycblt.auxio.util.update
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
import org.oxycblt.musikr.cover.Cover import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.fs.Format import org.oxycblt.musikr.fs.Format
@ -31,6 +29,8 @@ import org.oxycblt.musikr.tag.Date
import org.oxycblt.musikr.tag.Disc import org.oxycblt.musikr.tag.Disc
import org.oxycblt.musikr.tag.Name import org.oxycblt.musikr.tag.Name
import org.oxycblt.musikr.tag.ReleaseType import org.oxycblt.musikr.tag.ReleaseType
import org.oxycblt.musikr.tag.ReplayGainAdjustment
import org.oxycblt.musikr.util.update
data class PreSong( data class PreSong(
val musicBrainzId: UUID?, val musicBrainzId: UUID?,

View file

@ -19,8 +19,6 @@
package org.oxycblt.musikr.tag.interpret package org.oxycblt.musikr.tag.interpret
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
import org.oxycblt.auxio.util.toUuidOrNull
import org.oxycblt.musikr.Interpretation import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.fs.Format import org.oxycblt.musikr.fs.Format
import org.oxycblt.musikr.fs.query.DeviceFile import org.oxycblt.musikr.fs.query.DeviceFile
@ -28,8 +26,10 @@ import org.oxycblt.musikr.pipeline.RawSong
import org.oxycblt.musikr.tag.Disc import org.oxycblt.musikr.tag.Disc
import org.oxycblt.musikr.tag.Name import org.oxycblt.musikr.tag.Name
import org.oxycblt.musikr.tag.ReleaseType import org.oxycblt.musikr.tag.ReleaseType
import org.oxycblt.musikr.tag.ReplayGainAdjustment
import org.oxycblt.musikr.tag.parse.ParsedTags import org.oxycblt.musikr.tag.parse.ParsedTags
import org.oxycblt.musikr.tag.util.parseId3GenreNames import org.oxycblt.musikr.tag.util.parseId3GenreNames
import org.oxycblt.musikr.util.toUuidOrNull
interface TagInterpreter { interface TagInterpreter {
fun interpret(song: RawSong, interpretation: Interpretation): PreSong fun interpret(song: RawSong, interpretation: Interpretation): PreSong

View file

@ -19,11 +19,11 @@
package org.oxycblt.musikr.tag.parse package org.oxycblt.musikr.tag.parse
import androidx.core.text.isDigitsOnly import androidx.core.text.isDigitsOnly
import org.oxycblt.auxio.util.nonZeroOrNull
import org.oxycblt.ktaglib.Metadata import org.oxycblt.ktaglib.Metadata
import org.oxycblt.musikr.tag.Date import org.oxycblt.musikr.tag.Date
import org.oxycblt.musikr.tag.util.parseId3v2PositionField import org.oxycblt.musikr.tag.util.parseId3v2PositionField
import org.oxycblt.musikr.tag.util.parseXiphPositionField import org.oxycblt.musikr.tag.util.parseXiphPositionField
import org.oxycblt.musikr.util.nonZeroOrNull
// Song // Song
fun Metadata.musicBrainzId() = fun Metadata.musicBrainzId() =

View file

@ -18,7 +18,7 @@
package org.oxycblt.musikr.tag.util package org.oxycblt.musikr.tag.util
import org.oxycblt.auxio.util.positiveOrNull import org.oxycblt.musikr.util.positiveOrNull
/** /**
* Parse an ID3v2-style position + total [String] field. These fields consist of a number and an * Parse an ID3v2-style position + total [String] field. These fields consist of a number and an

View file

@ -0,0 +1,133 @@
/*
* Copyright (c) 2021 Auxio Project
* LangUtil.kt is part of Auxio.
*
* 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.musikr.util
import java.security.MessageDigest
import java.util.UUID
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.musikr.tag.Date
import kotlin.reflect.KClass
/**
* Sanitizes a value that is unlikely to be null. On debug builds, this aliases to [requireNotNull],
* otherwise, it aliases to the unchecked dereference operator (!!). This can be used as a minor
* optimization in certain cases.
*/
fun <T> unlikelyToBeNull(value: T?) =
if (BuildConfig.DEBUG) {
requireNotNull(value)
} else {
value!!
}
/**
* Aliases a check to ensure that the given number is non-zero.
*
* @return The given number if it's non-zero, null otherwise.
*/
fun Int.positiveOrNull() = if (this > 0) this else null
/**
* Aliases a check to ensure that the given number is non-zero.
*
* @return The same number if it's non-zero, null otherwise.
*/
fun Float.nonZeroOrNull() = if (this != 0f) this else null
/**
* Aliases a check to ensure a given value is in a specified range.
*
* @param range The valid range of values for this number.
* @return The same number if it is in the range, null otherwise.
*/
fun Int.inRangeOrNull(range: IntRange) = if (range.contains(this)) this else null
/**
* Convert a [String] to a [UUID].
*
* @return A [UUID] converted from the [String] value, or null if the value was not valid.
* @see UUID.fromString
*/
fun String.toUuidOrNull(): UUID? =
try {
UUID.fromString(this)
} catch (e: IllegalArgumentException) {
null
}
/**
* Update a [MessageDigest] with a lowercase [String].
*
* @param string The [String] to hash. If null, it will not be hashed.
*/
fun MessageDigest.update(string: String?) {
if (string != null) {
update(string.lowercase().toByteArray())
} else {
update(0)
}
}
/**
* Update a [MessageDigest] with the string representation of a [Date].
*
* @param date The [Date] to hash. If null, nothing will be done.
*/
fun MessageDigest.update(date: Date?) {
if (date != null) {
update(date.toString().toByteArray())
} else {
update(0)
}
}
/**
* Update a [MessageDigest] with the lowercase versions of all of the input [String]s.
*
* @param strings The [String]s to hash. If a [String] is null, it will not be hashed.
*/
fun MessageDigest.update(strings: List<String?>) {
strings.forEach(::update)
}
/**
* Update a [MessageDigest] with the little-endian bytes of a [Int].
*
* @param n The [Int] to write. If null, nothing will be done.
*/
fun MessageDigest.update(n: Int?) {
if (n != null) {
update(byteArrayOf(n.toByte(), n.shr(8).toByte(), n.shr(16).toByte(), n.shr(24).toByte()))
} else {
update(0)
}
}
/**
* 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 method The name of the method to obtain.
*/
fun lazyReflectedMethod(clazz: KClass<*>, method: String, vararg params: KClass<*>) = lazy {
clazz.java.getDeclaredMethod(method, *params.map { it.java }.toTypedArray()).also {
it.isAccessible = true
}
}