Fix existing linting problems
This commit is contained in:
parent
1b6a246411
commit
ef3387dee0
|
@ -241,13 +241,15 @@ project.afterEvaluate {
|
|||
sourceDirectories.setFrom(files(listOf(mainSrc)))
|
||||
classDirectories.setFrom(files(listOf(debugTree)))
|
||||
|
||||
executionData.setFrom(fileTree(project.buildDir) {
|
||||
setIncludes(
|
||||
listOf(
|
||||
"outputs/unit_test_code_coverage/debugUnitTest/*.exec",
|
||||
"outputs/code_coverage/debugAndroidTest/connected/**/*.ec"
|
||||
executionData.setFrom(
|
||||
fileTree(project.buildDir) {
|
||||
setIncludes(
|
||||
listOf(
|
||||
"outputs/unit_test_code_coverage/debugUnitTest/*.exec",
|
||||
"outputs/code_coverage/debugAndroidTest/connected/**/*.ec"
|
||||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,13 +5,18 @@ import android.content.Context
|
|||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import audio.funkwhale.ffa.koin.authModule
|
||||
import audio.funkwhale.ffa.koin.exoplayerModule
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.Request
|
||||
import com.preference.PowerPreference
|
||||
import kotlinx.coroutines.channels.BroadcastChannel
|
||||
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
||||
import org.koin.core.context.startKoin
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
class FFA : Application() {
|
||||
|
||||
|
|
|
@ -73,9 +73,9 @@ class DownloadsActivity : AppCompatActivity() {
|
|||
val download = cursor.download
|
||||
|
||||
download.getMetadata()?.let { info ->
|
||||
adapter.downloads.add(info.apply {
|
||||
this.download = download
|
||||
})
|
||||
adapter.downloads.add(
|
||||
info.apply { this.download = download }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,8 @@ class LicencesActivity : AppCompatActivity() {
|
|||
holder.licence.text = item.licence
|
||||
}
|
||||
|
||||
inner class ViewHolder(binding: RowLicenceBinding) : RecyclerView.ViewHolder(binding.root),
|
||||
inner class ViewHolder(binding: RowLicenceBinding) :
|
||||
RecyclerView.ViewHolder(binding.root),
|
||||
View.OnClickListener {
|
||||
val name = binding.name
|
||||
val licence = binding.licence
|
||||
|
|
|
@ -11,7 +11,10 @@ import androidx.lifecycle.lifecycleScope
|
|||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.databinding.ActivityLoginBinding
|
||||
import audio.funkwhale.ffa.fragments.LoginDialog
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.FuelResult
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.Userinfo
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import com.github.kittinunf.fuel.coroutines.awaitObjectResponseResult
|
||||
import com.github.kittinunf.fuel.gson.gsonDeserializerOf
|
||||
|
|
|
@ -9,7 +9,11 @@ import android.graphics.Bitmap
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.*
|
||||
import android.view.Gravity
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AccelerateDecelerateInterpolator
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
@ -24,7 +28,13 @@ import androidx.lifecycle.lifecycleScope
|
|||
import audio.funkwhale.ffa.FFA
|
||||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.databinding.ActivityMainBinding
|
||||
import audio.funkwhale.ffa.fragments.*
|
||||
import audio.funkwhale.ffa.fragments.AddToPlaylistDialog
|
||||
import audio.funkwhale.ffa.fragments.AlbumsFragment
|
||||
import audio.funkwhale.ffa.fragments.ArtistsFragment
|
||||
import audio.funkwhale.ffa.fragments.BrowseFragment
|
||||
import audio.funkwhale.ffa.fragments.LandscapeQueueFragment
|
||||
import audio.funkwhale.ffa.fragments.QueueFragment
|
||||
import audio.funkwhale.ffa.fragments.TrackInfoDetailsFragment
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.playback.MediaControlsManager
|
||||
import audio.funkwhale.ffa.playback.PinService
|
||||
|
@ -32,7 +42,25 @@ import audio.funkwhale.ffa.playback.PlayerService
|
|||
import audio.funkwhale.ffa.repositories.FavoritedRepository
|
||||
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
||||
import audio.funkwhale.ffa.repositories.Repository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.ProgressBus
|
||||
import audio.funkwhale.ffa.utils.Settings
|
||||
import audio.funkwhale.ffa.utils.Userinfo
|
||||
import audio.funkwhale.ffa.utils.authorize
|
||||
import audio.funkwhale.ffa.utils.log
|
||||
import audio.funkwhale.ffa.utils.logError
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.onApi
|
||||
import audio.funkwhale.ffa.utils.toast
|
||||
import audio.funkwhale.ffa.utils.untilNetwork
|
||||
import audio.funkwhale.ffa.views.DisableableFrameLayout
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import com.github.kittinunf.fuel.coroutines.awaitStringResponse
|
||||
|
@ -132,17 +160,17 @@ class MainActivity : AppCompatActivity() {
|
|||
}
|
||||
|
||||
binding.nowPlayingContainer?.nowPlayingDetailsProgress?.setOnSeekBarChangeListener(object :
|
||||
SeekBar.OnSeekBarChangeListener {
|
||||
override fun onStopTrackingTouch(view: SeekBar?) {}
|
||||
SeekBar.OnSeekBarChangeListener {
|
||||
override fun onStopTrackingTouch(view: SeekBar?) {}
|
||||
|
||||
override fun onStartTrackingTouch(view: SeekBar?) {}
|
||||
override fun onStartTrackingTouch(view: SeekBar?) {}
|
||||
|
||||
override fun onProgressChanged(view: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
CommandBus.send(Command.Seek(progress))
|
||||
override fun onProgressChanged(view: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
CommandBus.send(Command.Seek(progress))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
landscapeQueue?.let {
|
||||
supportFragmentManager.beginTransaction()
|
||||
|
@ -303,9 +331,11 @@ class MainActivity : AppCompatActivity() {
|
|||
when (message) {
|
||||
is Event.LogOut -> {
|
||||
FFA.get().deleteAllData(this@MainActivity)
|
||||
startActivity(Intent(this@MainActivity, LoginActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NO_HISTORY
|
||||
})
|
||||
startActivity(
|
||||
Intent(this@MainActivity, LoginActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_NO_HISTORY
|
||||
}
|
||||
)
|
||||
|
||||
finish()
|
||||
}
|
||||
|
@ -385,12 +415,15 @@ class MainActivity : AppCompatActivity() {
|
|||
PlayerService::class.java
|
||||
).apply {
|
||||
putExtra(PlayerService.INITIAL_COMMAND_KEY, command.command.toString())
|
||||
})
|
||||
}
|
||||
)
|
||||
},
|
||||
{
|
||||
startService(Intent(this@MainActivity, PlayerService::class.java).apply {
|
||||
putExtra(PlayerService.INITIAL_COMMAND_KEY, command.command.toString())
|
||||
})
|
||||
startService(
|
||||
Intent(this@MainActivity, PlayerService::class.java).apply {
|
||||
putExtra(PlayerService.INITIAL_COMMAND_KEY, command.command.toString())
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -13,15 +13,24 @@ import audio.funkwhale.ffa.fragments.AlbumsFragment
|
|||
import audio.funkwhale.ffa.fragments.ArtistsFragment
|
||||
import audio.funkwhale.ffa.model.Album
|
||||
import audio.funkwhale.ffa.model.Artist
|
||||
import audio.funkwhale.ffa.repositories.*
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.repositories.AlbumsSearchRepository
|
||||
import audio.funkwhale.ffa.repositories.ArtistsSearchRepository
|
||||
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
||||
import audio.funkwhale.ffa.repositories.Repository
|
||||
import audio.funkwhale.ffa.repositories.TracksSearchRepository
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.getMetadata
|
||||
import audio.funkwhale.ffa.utils.untilNetwork
|
||||
import com.google.android.exoplayer2.offline.Download
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.net.URLEncoder
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
|
||||
class SearchActivity : AppCompatActivity() {
|
||||
private lateinit var adapter: SearchAdapter
|
||||
|
@ -82,58 +91,58 @@ class SearchActivity : AppCompatActivity() {
|
|||
favoritesRepository = FavoritesRepository(this@SearchActivity)
|
||||
|
||||
binding.search.setOnQueryTextListener(object :
|
||||
androidx.appcompat.widget.SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(rawQuery: String?): Boolean {
|
||||
binding.search.clearFocus()
|
||||
androidx.appcompat.widget.SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(rawQuery: String?): Boolean {
|
||||
binding.search.clearFocus()
|
||||
|
||||
rawQuery?.let {
|
||||
done = 0
|
||||
rawQuery?.let {
|
||||
done = 0
|
||||
|
||||
val query = URLEncoder.encode(it, "UTF-8")
|
||||
val query = URLEncoder.encode(it, "UTF-8")
|
||||
|
||||
artistsRepository.query = query.lowercase(Locale.ROOT)
|
||||
albumsRepository.query = query.lowercase(Locale.ROOT)
|
||||
tracksRepository.query = query.lowercase(Locale.ROOT)
|
||||
artistsRepository.query = query.lowercase(Locale.ROOT)
|
||||
albumsRepository.query = query.lowercase(Locale.ROOT)
|
||||
tracksRepository.query = query.lowercase(Locale.ROOT)
|
||||
|
||||
binding.searchSpinner.visibility = View.VISIBLE
|
||||
binding.searchEmpty.visibility = View.GONE
|
||||
binding.searchNoResults.visibility = View.GONE
|
||||
binding.searchSpinner.visibility = View.VISIBLE
|
||||
binding.searchEmpty.visibility = View.GONE
|
||||
binding.searchNoResults.visibility = View.GONE
|
||||
|
||||
adapter.artists.clear()
|
||||
adapter.albums.clear()
|
||||
adapter.tracks.clear()
|
||||
adapter.notifyDataSetChanged()
|
||||
adapter.artists.clear()
|
||||
adapter.albums.clear()
|
||||
adapter.tracks.clear()
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
artistsRepository.fetch(Repository.Origin.Network.origin)
|
||||
.untilNetwork(lifecycleScope) { artists, _, _, _ ->
|
||||
done++
|
||||
artistsRepository.fetch(Repository.Origin.Network.origin)
|
||||
.untilNetwork(lifecycleScope) { artists, _, _, _ ->
|
||||
done++
|
||||
|
||||
adapter.artists.addAll(artists)
|
||||
refresh()
|
||||
}
|
||||
adapter.artists.addAll(artists)
|
||||
refresh()
|
||||
}
|
||||
|
||||
albumsRepository.fetch(Repository.Origin.Network.origin)
|
||||
.untilNetwork(lifecycleScope) { albums, _, _, _ ->
|
||||
done++
|
||||
albumsRepository.fetch(Repository.Origin.Network.origin)
|
||||
.untilNetwork(lifecycleScope) { albums, _, _, _ ->
|
||||
done++
|
||||
|
||||
adapter.albums.addAll(albums)
|
||||
refresh()
|
||||
}
|
||||
adapter.albums.addAll(albums)
|
||||
refresh()
|
||||
}
|
||||
|
||||
tracksRepository.fetch(Repository.Origin.Network.origin)
|
||||
.untilNetwork(lifecycleScope) { tracks, _, _, _ ->
|
||||
done++
|
||||
tracksRepository.fetch(Repository.Origin.Network.origin)
|
||||
.untilNetwork(lifecycleScope) { tracks, _, _, _ ->
|
||||
done++
|
||||
|
||||
adapter.tracks.addAll(tracks)
|
||||
refresh()
|
||||
}
|
||||
adapter.tracks.addAll(tracks)
|
||||
refresh()
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String?) = true
|
||||
})
|
||||
override fun onQueryTextChange(newText: String?) = true
|
||||
})
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
package audio.funkwhale.ffa.activities
|
||||
|
||||
import android.content.*
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
|
|
|
@ -6,7 +6,9 @@ import android.os.Bundle
|
|||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import audio.funkwhale.ffa.FFA
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.Settings
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
class SplashActivity : AppCompatActivity() {
|
||||
|
|
|
@ -4,9 +4,14 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.fragments.*
|
||||
import audio.funkwhale.ffa.fragments.AlbumsGridFragment
|
||||
import audio.funkwhale.ffa.fragments.ArtistsFragment
|
||||
import audio.funkwhale.ffa.fragments.FavoritesFragment
|
||||
import audio.funkwhale.ffa.fragments.PlaylistsFragment
|
||||
import audio.funkwhale.ffa.fragments.RadiosFragment
|
||||
|
||||
class BrowseTabsAdapter(val context: Fragment, manager: FragmentManager) : FragmentPagerAdapter(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
class BrowseTabsAdapter(val context: Fragment, manager: FragmentManager) :
|
||||
FragmentPagerAdapter(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
var tabs = mutableListOf<Fragment>()
|
||||
|
||||
override fun getCount() = 5
|
||||
|
|
|
@ -8,9 +8,9 @@ import android.view.ViewGroup
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.databinding.RowDownloadBinding
|
||||
import audio.funkwhale.ffa.playback.PinService
|
||||
import audio.funkwhale.ffa.model.DownloadInfo
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.playback.PinService
|
||||
import com.google.android.exoplayer2.offline.Download
|
||||
import com.google.android.exoplayer2.offline.DownloadService
|
||||
|
||||
|
|
|
@ -13,9 +13,9 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.databinding.RowTrackBinding
|
||||
import audio.funkwhale.ffa.fragments.FFAAdapter
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.toast
|
||||
|
|
|
@ -16,10 +16,10 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.databinding.RowTrackBinding
|
||||
import audio.funkwhale.ffa.fragments.FFAAdapter
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.model.PlaylistTrack
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.toast
|
||||
|
|
|
@ -9,10 +9,10 @@ import audio.funkwhale.ffa.R
|
|||
import audio.funkwhale.ffa.databinding.RowRadioBinding
|
||||
import audio.funkwhale.ffa.databinding.RowRadioHeaderBinding
|
||||
import audio.funkwhale.ffa.fragments.FFAAdapter
|
||||
import audio.funkwhale.ffa.model.Radio
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.model.Radio
|
||||
import audio.funkwhale.ffa.views.LoadingImageView
|
||||
import com.preference.PowerPreference
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
@ -42,8 +42,10 @@ class RadiosAdapter(
|
|||
|
||||
private val instanceRadios: List<Radio> by lazy {
|
||||
context?.let {
|
||||
return@lazy when (val username =
|
||||
PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS).getString("actor_username")) {
|
||||
return@lazy when (
|
||||
val username =
|
||||
PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS).getString("actor_username")
|
||||
) {
|
||||
"" -> listOf(
|
||||
Radio(
|
||||
0,
|
||||
|
@ -133,8 +135,9 @@ class RadiosAdapter(
|
|||
context?.let {
|
||||
when (position) {
|
||||
0 -> holder.label.text = context.getString(R.string.radio_instance_radios)
|
||||
instanceRadios.size + 1 -> holder.label.text =
|
||||
context.getString(R.string.radio_user_radios)
|
||||
instanceRadios.size + 1 ->
|
||||
holder.label.text =
|
||||
context.getString(R.string.radio_user_radios)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ import audio.funkwhale.ffa.databinding.RowSearchHeaderBinding
|
|||
import audio.funkwhale.ffa.databinding.RowTrackBinding
|
||||
import audio.funkwhale.ffa.model.Album
|
||||
import audio.funkwhale.ffa.model.Artist
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.onApi
|
||||
|
@ -73,20 +73,19 @@ class SearchAdapter(
|
|||
|
||||
ResultType.Artist.ordinal -> artists[position].id.toLong()
|
||||
ResultType.Artist.ordinal -> albums[position - artists.size - 2].id.toLong()
|
||||
ResultType.Track.ordinal -> tracks[position - artists.size - albums.size - sectionCount].id.toLong()
|
||||
ResultType.Track.ordinal ->
|
||||
tracks[position - artists.size - albums.size - sectionCount].id.toLong()
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
if (position == 0) return ResultType.Header.ordinal // Artists header
|
||||
if (position == (artists.size + 1)) return ResultType.Header.ordinal // Albums header
|
||||
if (position == (artists.size + albums.size + 2)) return ResultType.Header.ordinal // Tracks header
|
||||
|
||||
if (position <= artists.size) return ResultType.Artist.ordinal
|
||||
if (position <= artists.size + albums.size + 2) return ResultType.Album.ordinal
|
||||
|
||||
return ResultType.Track.ordinal
|
||||
override fun getItemViewType(position: Int): Int = when {
|
||||
position == 0 ||
|
||||
position == (artists.size + 1) ||
|
||||
position == (artists.size + albums.size + 2) -> ResultType.Header.ordinal
|
||||
position <= artists.size -> ResultType.Artist.ordinal
|
||||
position <= artists.size + albums.size + 2 -> ResultType.Album.ordinal
|
||||
else -> ResultType.Track.ordinal
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
|
@ -205,102 +204,112 @@ class SearchAdapter(
|
|||
Typeface.create(searchHeaderViewHolder?.title?.typeface, Typeface.NORMAL)
|
||||
rowTrackViewHolder?.artist?.typeface =
|
||||
Typeface.create(rowTrackViewHolder?.artist?.typeface, Typeface.NORMAL)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
searchHeaderViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
|
||||
|
||||
when (resultType) {
|
||||
ResultType.Artist.ordinal -> {
|
||||
rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
0, 0, 0, 0
|
||||
)
|
||||
}
|
||||
ResultType.Album.ordinal -> {
|
||||
rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
0, 0, 0, 0
|
||||
)
|
||||
}
|
||||
ResultType.Track.ordinal -> {
|
||||
(item as? Track)?.let { track ->
|
||||
context?.let { context ->
|
||||
if (track == currentTrack || track.current) {
|
||||
searchHeaderViewHolder?.title?.setTypeface(
|
||||
searchHeaderViewHolder.title.typeface,
|
||||
Typeface.BOLD
|
||||
)
|
||||
rowTrackViewHolder?.artist?.setTypeface(
|
||||
rowTrackViewHolder.artist.typeface,
|
||||
Typeface.BOLD
|
||||
)
|
||||
ResultType.Artist.ordinal -> {
|
||||
rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
0, 0, 0, 0
|
||||
)
|
||||
}
|
||||
ResultType.Album.ordinal -> {
|
||||
rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
0, 0, 0, 0
|
||||
)
|
||||
}
|
||||
ResultType.Track.ordinal -> {
|
||||
(item as? Track)?.let { track ->
|
||||
context?.let { context ->
|
||||
if (track == currentTrack || track.current) {
|
||||
searchHeaderViewHolder?.title?.setTypeface(
|
||||
searchHeaderViewHolder.title.typeface,
|
||||
Typeface.BOLD
|
||||
)
|
||||
rowTrackViewHolder?.artist?.setTypeface(
|
||||
rowTrackViewHolder.artist.typeface,
|
||||
Typeface.BOLD
|
||||
)
|
||||
}
|
||||
|
||||
when (track.favorite) {
|
||||
true -> rowTrackViewHolder?.favorite?.setColorFilter(
|
||||
context.getColor(R.color.colorFavorite)
|
||||
)
|
||||
false -> rowTrackViewHolder?.favorite?.setColorFilter(
|
||||
context.getColor(R.color.colorSelected)
|
||||
)
|
||||
}
|
||||
|
||||
rowTrackViewHolder?.favorite?.setOnClickListener {
|
||||
favoriteListener?.let {
|
||||
favoriteListener.onToggleFavorite(track.id, !track.favorite)
|
||||
|
||||
tracks[position - artists.size - albums.size - sectionCount].favorite =
|
||||
!track.favorite
|
||||
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
}
|
||||
|
||||
when (track.favorite) {
|
||||
true -> rowTrackViewHolder?.favorite?.setColorFilter(context.getColor(R.color.colorFavorite))
|
||||
false -> rowTrackViewHolder?.favorite?.setColorFilter(context.getColor(R.color.colorSelected))
|
||||
when (track.cached || track.downloaded) {
|
||||
true -> rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
R.drawable.downloaded, 0, 0, 0
|
||||
)
|
||||
false -> rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
0, 0, 0, 0
|
||||
)
|
||||
}
|
||||
|
||||
if (track.cached && !track.downloaded) {
|
||||
rowTrackViewHolder?.title?.compoundDrawables?.forEach {
|
||||
it?.colorFilter =
|
||||
PorterDuffColorFilter(context.getColor(R.color.cached), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
|
||||
rowTrackViewHolder?.favorite?.setOnClickListener {
|
||||
favoriteListener?.let {
|
||||
favoriteListener.onToggleFavorite(track.id, !track.favorite)
|
||||
|
||||
tracks[position - artists.size - albums.size - sectionCount].favorite =
|
||||
!track.favorite
|
||||
|
||||
notifyItemChanged(position)
|
||||
}
|
||||
if (track.downloaded) {
|
||||
rowTrackViewHolder?.title?.compoundDrawables?.forEach {
|
||||
it?.colorFilter =
|
||||
PorterDuffColorFilter(
|
||||
context.getColor(R.color.downloaded),
|
||||
PorterDuff.Mode.SRC_IN
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
when (track.cached || track.downloaded) {
|
||||
true -> rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
R.drawable.downloaded, 0, 0, 0
|
||||
)
|
||||
false -> rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
|
||||
0, 0, 0, 0
|
||||
)
|
||||
}
|
||||
rowTrackViewHolder?.actions?.setOnClickListener {
|
||||
PopupMenu(
|
||||
context,
|
||||
rowTrackViewHolder.actions,
|
||||
Gravity.START,
|
||||
R.attr.actionOverflowMenuStyle,
|
||||
0
|
||||
).apply {
|
||||
inflate(R.menu.row_track)
|
||||
|
||||
if (track.cached && !track.downloaded) {
|
||||
rowTrackViewHolder?.title?.compoundDrawables?.forEach {
|
||||
it?.colorFilter =
|
||||
PorterDuffColorFilter(context.getColor(R.color.cached), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
|
||||
if (track.downloaded) {
|
||||
rowTrackViewHolder?.title?.compoundDrawables?.forEach {
|
||||
it?.colorFilter =
|
||||
PorterDuffColorFilter(context.getColor(R.color.downloaded), PorterDuff.Mode.SRC_IN)
|
||||
}
|
||||
}
|
||||
|
||||
rowTrackViewHolder?.actions?.setOnClickListener {
|
||||
PopupMenu(
|
||||
context,
|
||||
rowTrackViewHolder.actions,
|
||||
Gravity.START,
|
||||
R.attr.actionOverflowMenuStyle,
|
||||
0
|
||||
).apply {
|
||||
inflate(R.menu.row_track)
|
||||
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.track_add_to_queue -> CommandBus.send(Command.AddToQueue(listOf(track)))
|
||||
R.id.track_play_next -> CommandBus.send(Command.PlayNext(track))
|
||||
R.id.track_pin -> CommandBus.send(Command.PinTrack(track))
|
||||
R.id.track_add_to_playlist -> CommandBus.send(Command.AddToPlaylist(listOf(track)))
|
||||
R.id.queue_remove -> CommandBus.send(Command.RemoveFromQueue(track))
|
||||
}
|
||||
|
||||
true
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.track_add_to_queue -> CommandBus.send(Command.AddToQueue(listOf(track)))
|
||||
R.id.track_play_next -> CommandBus.send(Command.PlayNext(track))
|
||||
R.id.track_pin -> CommandBus.send(Command.PinTrack(track))
|
||||
R.id.track_add_to_playlist -> CommandBus.send(
|
||||
Command.AddToPlaylist(listOf(track))
|
||||
)
|
||||
R.id.queue_remove -> CommandBus.send(Command.RemoveFromQueue(track))
|
||||
}
|
||||
|
||||
show()
|
||||
true
|
||||
}
|
||||
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,9 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.databinding.RowTrackBinding
|
||||
import audio.funkwhale.ffa.fragments.FFAAdapter
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.toast
|
||||
|
|
|
@ -14,7 +14,8 @@ import audio.funkwhale.ffa.databinding.DialogAddToPlaylistBinding
|
|||
import audio.funkwhale.ffa.model.Playlist
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.repositories.ManagementPlaylistsRepository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.untilNetwork
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
@ -80,19 +81,22 @@ object AddToPlaylistDialog {
|
|||
}
|
||||
|
||||
val adapter =
|
||||
PlaylistsAdapter(layoutInflater, activity, object : PlaylistsAdapter.OnPlaylistClickListener {
|
||||
override fun onClick(holder: View?, playlist: Playlist) {
|
||||
repository.add(playlist.id, tracks)
|
||||
PlaylistsAdapter(
|
||||
layoutInflater, activity,
|
||||
object : PlaylistsAdapter.OnPlaylistClickListener {
|
||||
override fun onClick(holder: View?, playlist: Playlist) {
|
||||
repository.add(playlist.id, tracks)
|
||||
|
||||
Toast.makeText(
|
||||
activity,
|
||||
activity.getString(R.string.playlist_added_to, playlist.name),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
Toast.makeText(
|
||||
activity,
|
||||
activity.getString(R.string.playlist_added_to, playlist.name),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
dialog.dismiss()
|
||||
dialog.dismiss()
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
binding.playlists.layoutManager = LinearLayoutManager(activity)
|
||||
binding.playlists.adapter = adapter
|
||||
|
|
|
@ -25,7 +25,12 @@ import audio.funkwhale.ffa.model.Artist
|
|||
import audio.funkwhale.ffa.repositories.AlbumsRepository
|
||||
import audio.funkwhale.ffa.repositories.ArtistTracksRepository
|
||||
import audio.funkwhale.ffa.repositories.Repository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.onViewPager
|
||||
import com.squareup.picasso.Picasso
|
||||
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
|
|
@ -13,8 +13,8 @@ import audio.funkwhale.ffa.R
|
|||
import audio.funkwhale.ffa.activities.MainActivity
|
||||
import audio.funkwhale.ffa.adapters.AlbumsGridAdapter
|
||||
import audio.funkwhale.ffa.databinding.FragmentAlbumsGridBinding
|
||||
import audio.funkwhale.ffa.repositories.AlbumsRepository
|
||||
import audio.funkwhale.ffa.model.Album
|
||||
import audio.funkwhale.ffa.repositories.AlbumsRepository
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
|
||||
class AlbumsGridFragment : FFAFragment<Album, AlbumsGridAdapter>() {
|
||||
|
|
|
@ -10,7 +10,10 @@ import androidx.recyclerview.widget.SimpleItemAnimator
|
|||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
import audio.funkwhale.ffa.repositories.HttpUpstream
|
||||
import audio.funkwhale.ffa.repositories.Repository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.untilNetwork
|
||||
import com.google.gson.Gson
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
|
|
|
@ -11,7 +11,15 @@ import audio.funkwhale.ffa.databinding.FragmentFavoritesBinding
|
|||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
||||
import audio.funkwhale.ffa.repositories.TracksRepository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.Request
|
||||
import audio.funkwhale.ffa.utils.RequestBus
|
||||
import audio.funkwhale.ffa.utils.Response
|
||||
import audio.funkwhale.ffa.utils.getMetadata
|
||||
import audio.funkwhale.ffa.utils.wait
|
||||
import com.google.android.exoplayer2.offline.Download
|
||||
import com.google.android.exoplayer2.offline.DownloadManager
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
|
|
@ -18,7 +18,15 @@ import audio.funkwhale.ffa.model.Track
|
|||
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
||||
import audio.funkwhale.ffa.repositories.ManagementPlaylistsRepository
|
||||
import audio.funkwhale.ffa.repositories.PlaylistTracksRepository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Request
|
||||
import audio.funkwhale.ffa.utils.RequestBus
|
||||
import audio.funkwhale.ffa.utils.Response
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.toast
|
||||
import audio.funkwhale.ffa.utils.wait
|
||||
import com.squareup.picasso.Picasso
|
||||
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
|
|
|
@ -12,9 +12,9 @@ import audio.funkwhale.ffa.R
|
|||
import audio.funkwhale.ffa.activities.MainActivity
|
||||
import audio.funkwhale.ffa.adapters.PlaylistsAdapter
|
||||
import audio.funkwhale.ffa.databinding.FragmentPlaylistsBinding
|
||||
import audio.funkwhale.ffa.model.Playlist
|
||||
import audio.funkwhale.ffa.repositories.PlaylistsRepository
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.model.Playlist
|
||||
|
||||
class PlaylistsFragment : FFAFragment<Playlist, PlaylistsAdapter>() {
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import audio.funkwhale.ffa.adapters.RadiosAdapter
|
||||
import audio.funkwhale.ffa.databinding.FragmentRadiosBinding
|
||||
import audio.funkwhale.ffa.model.Radio
|
||||
import audio.funkwhale.ffa.repositories.RadiosRepository
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.model.Radio
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
|
|
|
@ -19,7 +19,18 @@ import audio.funkwhale.ffa.model.Track
|
|||
import audio.funkwhale.ffa.repositories.FavoritedRepository
|
||||
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
||||
import audio.funkwhale.ffa.repositories.TracksRepository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.Request
|
||||
import audio.funkwhale.ffa.utils.RequestBus
|
||||
import audio.funkwhale.ffa.utils.Response
|
||||
import audio.funkwhale.ffa.utils.getMetadata
|
||||
import audio.funkwhale.ffa.utils.maybeLoad
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.toast
|
||||
import audio.funkwhale.ffa.utils.wait
|
||||
import com.google.android.exoplayer2.offline.Download
|
||||
import com.google.android.exoplayer2.offline.DownloadManager
|
||||
import com.preference.PowerPreference
|
||||
|
@ -199,8 +210,10 @@ class TracksFragment : FFAFragment<Track, TracksAdapter>() {
|
|||
|
||||
setOnMenuItemClickListener {
|
||||
when (it.itemId) {
|
||||
R.id.play_secondary -> when (PowerPreference.getDefaultFile()
|
||||
.getString("play_order")) {
|
||||
R.id.play_secondary -> when (
|
||||
PowerPreference.getDefaultFile()
|
||||
.getString("play_order")
|
||||
) {
|
||||
"in_order" -> CommandBus.send(Command.ReplaceQueue(adapter.data.shuffled()))
|
||||
else -> CommandBus.send(Command.ReplaceQueue(adapter.data))
|
||||
}
|
||||
|
|
|
@ -64,4 +64,4 @@ fun exoplayerModule(context: Context) = module {
|
|||
fun authModule() = module {
|
||||
single { OAuth(get()) }
|
||||
single { AuthorizationServiceFactory() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ data class AlbumsResponse(
|
|||
val results: AlbumList
|
||||
) : FFAResponse<Album>() {
|
||||
override fun getData() = results
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,4 +13,4 @@ data class Artist(
|
|||
override fun cover(): String? = albums?.getOrNull(0)?.cover?.urls?.original
|
||||
override fun title() = name
|
||||
override fun subtitle() = "Artist"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ data class ArtistsResponse(
|
|||
val results: List<Artist>
|
||||
) : FFAResponse<Artist>() {
|
||||
override fun getData() = results
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,4 +9,4 @@ class PlaylistsCache(data: List<Playlist>) : CacheItem<Playlist>(data)
|
|||
class PlaylistTracksCache(data: List<PlaylistTrack>) : CacheItem<PlaylistTrack>(data)
|
||||
class RadiosCache(data: List<Radio>) : CacheItem<Radio>(data)
|
||||
class FavoritedCache(data: List<Int>) : CacheItem<Int>(data)
|
||||
class QueueCache(data: List<Track>) : CacheItem<Track>(data)
|
||||
class QueueCache(data: List<Track>) : CacheItem<Track>(data)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package audio.funkwhale.ffa.model
|
||||
|
||||
data class CoverUrls(val original: String)
|
||||
data class CoverUrls(val original: String)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package audio.funkwhale.ffa.model
|
||||
|
||||
data class Covers(val urls: CoverUrls)
|
||||
data class Covers(val urls: CoverUrls)
|
||||
|
|
|
@ -8,4 +8,4 @@ data class DownloadInfo(
|
|||
val title: String,
|
||||
val artist: String,
|
||||
var download: Download?
|
||||
)
|
||||
)
|
||||
|
|
|
@ -5,4 +5,4 @@ abstract class FFAResponse<D : Any> {
|
|||
abstract val next: String?
|
||||
|
||||
abstract fun getData(): List<D>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package audio.funkwhale.ffa.model
|
||||
|
||||
data class Favorited(val track: Int)
|
||||
data class Favorited(val track: Int)
|
||||
|
|
|
@ -6,4 +6,4 @@ data class FavoritedResponse(
|
|||
val results: List<Favorited>
|
||||
) : FFAResponse<Int>() {
|
||||
override fun getData() = results.map { it.track }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ data class Playlist(
|
|||
val album_covers: List<String>,
|
||||
val tracks_count: Int,
|
||||
val duration: Int
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
package audio.funkwhale.ffa.model
|
||||
|
||||
data class PlaylistTrack(val track: Track)
|
||||
data class PlaylistTrack(val track: Track)
|
||||
|
|
|
@ -6,4 +6,4 @@ data class PlaylistTracksResponse(
|
|||
val results: List<PlaylistTrack>
|
||||
) : FFAResponse<PlaylistTrack>() {
|
||||
override fun getData() = results
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ data class PlaylistsResponse(
|
|||
val results: List<Playlist>
|
||||
) : FFAResponse<Playlist>() {
|
||||
override fun getData() = results
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ data class Radio(
|
|||
val name: String,
|
||||
val description: String,
|
||||
var related_object_id: String? = null
|
||||
)
|
||||
)
|
||||
|
|
|
@ -6,4 +6,4 @@ data class RadiosResponse(
|
|||
val results: List<Radio>
|
||||
) : FFAResponse<Radio>() {
|
||||
override fun getData() = results
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,4 +4,4 @@ interface SearchResult {
|
|||
fun cover(): String?
|
||||
fun title(): String
|
||||
fun subtitle(): String
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,4 +61,4 @@ data class Track(
|
|||
override fun subtitle() = artist.name
|
||||
|
||||
val formatted: String get() = "$id $artist ($album): $title"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@ data class TracksResponse(
|
|||
val results: List<Track>
|
||||
) : FFAResponse<Track>() {
|
||||
override fun getData() = results
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import audio.funkwhale.ffa.R
|
|||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.Settings
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
|
||||
import com.google.android.exoplayer2.upstream.FileDataSource
|
||||
import com.google.android.exoplayer2.upstream.cache.Cache
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
|
||||
|
@ -33,13 +33,13 @@ class CacheDataSourceFactoryProvider(
|
|||
}
|
||||
|
||||
private fun createDatasourceFactory(context: Context, oAuth: OAuth): DataSource.Factory {
|
||||
val http = DefaultHttpDataSourceFactory(
|
||||
Util.getUserAgent(context, context.getString(R.string.app_name))
|
||||
)
|
||||
val http = DefaultHttpDataSource.Factory().apply {
|
||||
setUserAgent(Util.getUserAgent(context, context.getString(R.string.app_name)))
|
||||
}
|
||||
return if (!Settings.isAnonymous()) {
|
||||
OAuth2DatasourceFactory(context, http, oAuth)
|
||||
} else {
|
||||
http
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ import androidx.media.app.NotificationCompat.MediaStyle
|
|||
import androidx.media.session.MediaButtonReceiver
|
||||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.activities.MainActivity
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
|
|
|
@ -44,11 +44,13 @@ class MediaSession(private val context: Context) {
|
|||
|
||||
it.setMediaButtonEventHandler { _, _, intent ->
|
||||
if (!active) {
|
||||
context.startService(Intent(context, PlayerService::class.java).apply {
|
||||
action = intent.action
|
||||
context.startService(
|
||||
Intent(context, PlayerService::class.java).apply {
|
||||
action = intent.action
|
||||
|
||||
intent.extras?.let { extras -> putExtras(extras) }
|
||||
})
|
||||
intent.extras?.let { extras -> putExtras(extras) }
|
||||
}
|
||||
)
|
||||
|
||||
return@setMediaButtonEventHandler true
|
||||
}
|
||||
|
|
|
@ -3,7 +3,11 @@ package audio.funkwhale.ffa.playback
|
|||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import com.google.android.exoplayer2.upstream.*
|
||||
import com.google.android.exoplayer2.upstream.DataSource
|
||||
import com.google.android.exoplayer2.upstream.DataSpec
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource
|
||||
import com.google.android.exoplayer2.upstream.TransferListener
|
||||
|
||||
class OAuthDatasource(
|
||||
private val context: Context,
|
||||
|
@ -38,7 +42,7 @@ class OAuthDatasource(
|
|||
|
||||
class OAuth2DatasourceFactory(
|
||||
private val context: Context,
|
||||
private val http: DefaultHttpDataSourceFactory,
|
||||
private val http: DefaultHttpDataSource.Factory,
|
||||
private val oauth: OAuth
|
||||
) : DataSource.Factory {
|
||||
|
||||
|
|
|
@ -7,7 +7,13 @@ import androidx.core.net.toUri
|
|||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.model.DownloadInfo
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.Request
|
||||
import audio.funkwhale.ffa.utils.RequestBus
|
||||
import audio.funkwhale.ffa.utils.Response
|
||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||
import com.google.android.exoplayer2.offline.Download
|
||||
import com.google.android.exoplayer2.offline.DownloadManager
|
||||
import com.google.android.exoplayer2.offline.DownloadRequest
|
||||
|
@ -21,7 +27,7 @@ import kotlinx.coroutines.Job
|
|||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.java.KoinJavaComponent
|
||||
import java.util.*
|
||||
import java.util.Collections
|
||||
|
||||
class PinService : DownloadService(AppContext.NOTIFICATION_DOWNLOADS) {
|
||||
|
||||
|
|
|
@ -17,7 +17,19 @@ import androidx.core.app.NotificationManagerCompat
|
|||
import androidx.media.session.MediaButtonReceiver
|
||||
import audio.funkwhale.ffa.R
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.HeadphonesUnpluggedReceiver
|
||||
import audio.funkwhale.ffa.utils.ProgressBus
|
||||
import audio.funkwhale.ffa.utils.Request
|
||||
import audio.funkwhale.ffa.utils.RequestBus
|
||||
import audio.funkwhale.ffa.utils.Response
|
||||
import audio.funkwhale.ffa.utils.log
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.onApi
|
||||
import com.google.android.exoplayer2.C
|
||||
import com.google.android.exoplayer2.ExoPlaybackException
|
||||
import com.google.android.exoplayer2.Player
|
||||
|
@ -25,10 +37,15 @@ import com.google.android.exoplayer2.SimpleExoPlayer
|
|||
import com.google.android.exoplayer2.source.TrackGroupArray
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.koin.java.KoinJavaComponent.inject
|
||||
|
||||
class PlayerService : Service() {
|
||||
|
@ -97,15 +114,17 @@ class PlayerService : Service() {
|
|||
|
||||
Build.VERSION_CODES.O.onApi {
|
||||
audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
|
||||
setAudioAttributes(AudioAttributes.Builder().run {
|
||||
setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
setAudioAttributes(
|
||||
AudioAttributes.Builder().run {
|
||||
setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
|
||||
setAcceptsDelayedFocusGain(true)
|
||||
setOnAudioFocusChangeListener(audioFocusChangeListener)
|
||||
setAcceptsDelayedFocusGain(true)
|
||||
setOnAudioFocusChangeListener(audioFocusChangeListener)
|
||||
|
||||
build()
|
||||
})
|
||||
build()
|
||||
}
|
||||
)
|
||||
|
||||
build()
|
||||
}
|
||||
|
@ -268,7 +287,8 @@ class PlayerService : Service() {
|
|||
{
|
||||
@Suppress("DEPRECATION")
|
||||
audioManager.abandonAudioFocus(audioFocusChangeListener)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
player.removeListener(playerEventListener)
|
||||
setPlaybackState(false)
|
||||
|
@ -461,7 +481,7 @@ class PlayerService : Service() {
|
|||
}
|
||||
|
||||
if (queue.get().isNotEmpty() && queue.current() == queue.get()
|
||||
.last() && radioPlayer.isActive()
|
||||
.last() && radioPlayer.isActive()
|
||||
) {
|
||||
scope.launch(IO) {
|
||||
if (radioPlayer.lock.tryAcquire()) {
|
||||
|
|
|
@ -4,7 +4,13 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import audio.funkwhale.ffa.model.QueueCache
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.log
|
||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||
import com.github.kittinunf.fuel.gson.gsonDeserializerOf
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource
|
||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
||||
|
@ -28,12 +34,14 @@ class QueueManager(val context: Context) {
|
|||
|
||||
val factory = cacheDataSourceFactoryProvider.create(context)
|
||||
|
||||
dataSources.addMediaSources(metadata.map { track ->
|
||||
val url = mustNormalizeUrl(track.bestUpload()?.listen_url ?: "")
|
||||
dataSources.addMediaSources(
|
||||
metadata.map { track ->
|
||||
val url = mustNormalizeUrl(track.bestUpload()?.listen_url ?: "")
|
||||
|
||||
ProgressiveMediaSource.Factory(factory).setTag(track.title)
|
||||
.createMediaSource(Uri.parse(url))
|
||||
})
|
||||
ProgressiveMediaSource.Factory(factory).setTag(track.title)
|
||||
.createMediaSource(Uri.parse(url))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,16 @@ import audio.funkwhale.ffa.model.Radio
|
|||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.repositories.FavoritedRepository
|
||||
import audio.funkwhale.ffa.repositories.Repository
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.Command
|
||||
import audio.funkwhale.ffa.utils.CommandBus
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.authorize
|
||||
import audio.funkwhale.ffa.utils.logError
|
||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.toast
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import com.github.kittinunf.fuel.coroutines.awaitObjectResponseResult
|
||||
import com.github.kittinunf.fuel.coroutines.awaitObjectResult
|
||||
|
|
|
@ -1,8 +1,19 @@
|
|||
package audio.funkwhale.ffa.repositories
|
||||
|
||||
import android.content.Context
|
||||
import audio.funkwhale.ffa.model.*
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.model.FFAResponse
|
||||
import audio.funkwhale.ffa.model.FavoritedCache
|
||||
import audio.funkwhale.ffa.model.FavoritedResponse
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.model.TracksCache
|
||||
import audio.funkwhale.ffa.model.TracksResponse
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.Settings
|
||||
import audio.funkwhale.ffa.utils.authorize
|
||||
import audio.funkwhale.ffa.utils.maybeNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||
import audio.funkwhale.ffa.utils.untilNetwork
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import com.github.kittinunf.fuel.coroutines.awaitByteArrayResponseResult
|
||||
import com.github.kittinunf.fuel.gson.gsonDeserializerOf
|
||||
|
|
|
@ -4,7 +4,14 @@ import android.content.Context
|
|||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import audio.funkwhale.ffa.model.FFAResponse
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.Event
|
||||
import audio.funkwhale.ffa.utils.EventBus
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.RefreshError
|
||||
import audio.funkwhale.ffa.utils.Settings
|
||||
import audio.funkwhale.ffa.utils.authorize
|
||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||
import com.github.kittinunf.fuel.Fuel
|
||||
import com.github.kittinunf.fuel.core.FuelError
|
||||
import com.github.kittinunf.fuel.core.ResponseDeserializable
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package audio.funkwhale.ffa.repositories
|
||||
|
||||
import android.content.Context
|
||||
import audio.funkwhale.ffa.model.*
|
||||
import audio.funkwhale.ffa.model.FFAResponse
|
||||
import audio.funkwhale.ffa.model.Playlist
|
||||
import audio.funkwhale.ffa.model.PlaylistsCache
|
||||
import audio.funkwhale.ffa.model.PlaylistsResponse
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.Settings
|
||||
import audio.funkwhale.ffa.utils.authorize
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package audio.funkwhale.ffa.repositories
|
||||
|
||||
import android.content.Context
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.model.CacheItem
|
||||
import audio.funkwhale.ffa.utils.AppContext
|
||||
import audio.funkwhale.ffa.utils.FFACache
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import java.io.BufferedReader
|
||||
import kotlin.math.ceil
|
||||
|
||||
|
@ -59,7 +63,7 @@ abstract class Repository<D : Any, C : CacheItem<D>> {
|
|||
}
|
||||
}.flowOn(IO)
|
||||
|
||||
private fun fromNetwork(size: Int) = flow {
|
||||
private fun fromNetwork(size: Int): Flow<Response<D>> = flow {
|
||||
upstream
|
||||
.fetch(size)
|
||||
.map { response ->
|
||||
|
|
|
@ -1,8 +1,17 @@
|
|||
package audio.funkwhale.ffa.repositories
|
||||
|
||||
import android.content.Context
|
||||
import audio.funkwhale.ffa.model.*
|
||||
import audio.funkwhale.ffa.utils.*
|
||||
import audio.funkwhale.ffa.model.Album
|
||||
import audio.funkwhale.ffa.model.AlbumsCache
|
||||
import audio.funkwhale.ffa.model.AlbumsResponse
|
||||
import audio.funkwhale.ffa.model.Artist
|
||||
import audio.funkwhale.ffa.model.ArtistsCache
|
||||
import audio.funkwhale.ffa.model.ArtistsResponse
|
||||
import audio.funkwhale.ffa.model.Track
|
||||
import audio.funkwhale.ffa.model.TracksCache
|
||||
import audio.funkwhale.ffa.model.TracksResponse
|
||||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import audio.funkwhale.ffa.utils.mustNormalizeUrl
|
||||
import com.github.kittinunf.fuel.gson.gsonDeserializerOf
|
||||
import com.google.android.exoplayer2.offline.DownloadManager
|
||||
import com.google.android.exoplayer2.upstream.cache.Cache
|
||||
|
|
|
@ -23,7 +23,7 @@ import kotlinx.coroutines.launch
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import net.openid.appauth.ClientSecretPost
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.Date
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
inline fun <D> Flow<Repository.Response<D>>.untilNetwork(
|
||||
|
@ -106,4 +106,4 @@ val ISO_8601_DATE_TIME_FORMAT = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
|||
|
||||
fun Date.format(): String {
|
||||
return ISO_8601_DATE_TIME_FORMAT.format(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,4 +19,4 @@ data class FuelResult(val httpStatus: Int? = null, val message: String? = null)
|
|||
return FuelResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,16 @@ import com.github.kittinunf.fuel.gson.jsonBody
|
|||
import com.github.kittinunf.result.Result
|
||||
import com.preference.PowerPreference
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.openid.appauth.*
|
||||
import net.openid.appauth.AuthState
|
||||
import net.openid.appauth.AuthorizationException
|
||||
import net.openid.appauth.AuthorizationRequest
|
||||
import net.openid.appauth.AuthorizationResponse
|
||||
import net.openid.appauth.AuthorizationService
|
||||
import net.openid.appauth.AuthorizationServiceConfiguration
|
||||
import net.openid.appauth.ClientSecretPost
|
||||
import net.openid.appauth.RegistrationRequest
|
||||
import net.openid.appauth.RegistrationResponse
|
||||
import net.openid.appauth.ResponseTypeValues
|
||||
|
||||
fun AuthState.save() {
|
||||
PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS).apply {
|
||||
|
@ -56,11 +65,13 @@ class OAuth(private val authorizationServiceFactory: AuthorizationServiceFactory
|
|||
|
||||
fun isAuthorized(context: Context): Boolean {
|
||||
val state = tryState()
|
||||
return (if (state != null) {
|
||||
state.validAuthorization() || refreshAccessToken(state, context)
|
||||
} else {
|
||||
false
|
||||
}).also {
|
||||
return (
|
||||
if (state != null) {
|
||||
state.validAuthorization() || refreshAccessToken(state, context)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
).also {
|
||||
it.logInfo("isAuthorized()")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,4 +58,4 @@ class FFATest {
|
|||
|
||||
expectThat(picassoCache.exists()).isFalse()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,4 +24,4 @@ class KoinTestApp : Application() {
|
|||
block()
|
||||
unloadKoinModules(module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,10 @@ import audio.funkwhale.ffa.KoinTestApp
|
|||
import audio.funkwhale.ffa.utils.OAuth
|
||||
import com.preference.PowerPreference
|
||||
import com.preference.Preference
|
||||
import io.mockk.*
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.verify
|
||||
import org.junit.After
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
|
Loading…
Reference in New Issue