Merge branch 'housekeeping/fix-linting-problems' into 'develop'

Fix existing linting problems

See merge request funkwhale/funkwhale-android!100
This commit is contained in:
Ryan Harg 2021-09-09 08:11:41 +00:00
commit 70feb589fa
64 changed files with 486 additions and 271 deletions

View File

@ -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"
)
)
)
})
}
)
}
}

View File

@ -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() {

View File

@ -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 }
)
}
}

View File

@ -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

View File

@ -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

View File

@ -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())
}
)
}
)
}

View File

@ -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() {

View File

@ -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

View File

@ -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() {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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()
}
}
}
}
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>() {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>() {

View File

@ -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

View File

@ -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))
}

View File

@ -64,4 +64,4 @@ fun exoplayerModule(context: Context) = module {
fun authModule() = module {
single { OAuth(get()) }
single { AuthorizationServiceFactory() }
}
}

View File

@ -6,4 +6,4 @@ data class AlbumsResponse(
val results: AlbumList
) : FFAResponse<Album>() {
override fun getData() = results
}
}

View File

@ -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"
}
}

View File

@ -6,4 +6,4 @@ data class ArtistsResponse(
val results: List<Artist>
) : FFAResponse<Artist>() {
override fun getData() = results
}
}

View File

@ -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)

View File

@ -1,3 +1,3 @@
package audio.funkwhale.ffa.model
data class CoverUrls(val original: String)
data class CoverUrls(val original: String)

View File

@ -1,3 +1,3 @@
package audio.funkwhale.ffa.model
data class Covers(val urls: CoverUrls)
data class Covers(val urls: CoverUrls)

View File

@ -8,4 +8,4 @@ data class DownloadInfo(
val title: String,
val artist: String,
var download: Download?
)
)

View File

@ -5,4 +5,4 @@ abstract class FFAResponse<D : Any> {
abstract val next: String?
abstract fun getData(): List<D>
}
}

View File

@ -1,3 +1,3 @@
package audio.funkwhale.ffa.model
data class Favorited(val track: Int)
data class Favorited(val track: Int)

View File

@ -6,4 +6,4 @@ data class FavoritedResponse(
val results: List<Favorited>
) : FFAResponse<Int>() {
override fun getData() = results.map { it.track }
}
}

View File

@ -6,4 +6,4 @@ data class Playlist(
val album_covers: List<String>,
val tracks_count: Int,
val duration: Int
)
)

View File

@ -1,3 +1,3 @@
package audio.funkwhale.ffa.model
data class PlaylistTrack(val track: Track)
data class PlaylistTrack(val track: Track)

View File

@ -6,4 +6,4 @@ data class PlaylistTracksResponse(
val results: List<PlaylistTrack>
) : FFAResponse<PlaylistTrack>() {
override fun getData() = results
}
}

View File

@ -6,4 +6,4 @@ data class PlaylistsResponse(
val results: List<Playlist>
) : FFAResponse<Playlist>() {
override fun getData() = results
}
}

View File

@ -6,4 +6,4 @@ data class Radio(
val name: String,
val description: String,
var related_object_id: String? = null
)
)

View File

@ -6,4 +6,4 @@ data class RadiosResponse(
val results: List<Radio>
) : FFAResponse<Radio>() {
override fun getData() = results
}
}

View File

@ -4,4 +4,4 @@ interface SearchResult {
fun cover(): String?
fun title(): String
fun subtitle(): String
}
}

View File

@ -61,4 +61,4 @@ data class Track(
override fun subtitle() = artist.name
val formatted: String get() = "$id $artist ($album): $title"
}
}

View File

@ -6,4 +6,4 @@ data class TracksResponse(
val results: List<Track>
) : FFAResponse<Track>() {
override fun getData() = results
}
}

View File

@ -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
}
}
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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) {

View File

@ -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()) {

View File

@ -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))
}
)
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ->

View File

@ -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

View File

@ -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)
}
}

View File

@ -19,4 +19,4 @@ data class FuelResult(val httpStatus: Int? = null, val message: String? = null)
return FuelResult()
}
}
}
}

View File

@ -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()")
}
}

View File

@ -58,4 +58,4 @@ class FFATest {
expectThat(picassoCache.exists()).isFalse()
}
}
}

View File

@ -24,4 +24,4 @@ class KoinTestApp : Application() {
block()
unloadKoinModules(module)
}
}
}

View File

@ -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