diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 22fd8e57174415c03f67a2590d820ed836d7a7a5..24b5dbc94ae6da078da49f7a1dda9ccb941c6597 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -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"
+          )
         )
-      )
-    })
+      }
+    )
   }
 }
diff --git a/app/src/main/java/audio/funkwhale/ffa/FFA.kt b/app/src/main/java/audio/funkwhale/ffa/FFA.kt
index e0002a62cc909adbbfc814c0771e42e6d2a4677b..e5299403ffa597134678fe05bddbe54bb1602a3b 100644
--- a/app/src/main/java/audio/funkwhale/ffa/FFA.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/FFA.kt
@@ -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() {
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/DownloadsActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/DownloadsActivity.kt
index 31711a35fa3a23936d370e42697210765ad9fbac..c5a34082bb5a712f3baf6f7d1a2d293341048cc7 100644
--- a/app/src/main/java/audio/funkwhale/ffa/activities/DownloadsActivity.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/activities/DownloadsActivity.kt
@@ -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 }
+          )
         }
       }
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/LicencesActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/LicencesActivity.kt
index 71d088c6fda8b3b964836d73f1b46bd4ece4320b..3de5e50466037ad7d1857016220f7a290eafec15 100644
--- a/app/src/main/java/audio/funkwhale/ffa/activities/LicencesActivity.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/activities/LicencesActivity.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt
index 2b78bb9ab18b42923513d7027cb483545b07dc89..862e3cc09325899dd968e977e996dca4ac44de18 100644
--- a/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/activities/LoginActivity.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt
index ccddeaed1682350fdba68cfadb1b5384f55e320f..fc01c5bbf1d2822c9da9d2df40be08754d4e17eb 100644
--- a/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/activities/MainActivity.kt
@@ -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())
+                  }
+                )
               }
             )
           }
diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/SearchActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/SearchActivity.kt
index 0a530bc7dc271efc821f123e8da012872c84ebcf..b5b574cf69541dd2e7e9682c74951ea17c6e9eb8 100644
--- a/app/src/main/java/audio/funkwhale/ffa/activities/SearchActivity.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/activities/SearchActivity.kt
@@ -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() {
diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt
index caa7a87aa4ee5923d61e7d64bcda7d239729ee40..38886ec7fd348c8216d0e0b16900db7c76160e15 100644
--- a/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/activities/SettingsActivity.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/activities/SplashActivity.kt b/app/src/main/java/audio/funkwhale/ffa/activities/SplashActivity.kt
index 865463d7545a3bed11c6a2bdfde5fd002d577bee..bce7f49ee80013c1d7170cf09f36fd2e6a0502c4 100644
--- a/app/src/main/java/audio/funkwhale/ffa/activities/SplashActivity.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/activities/SplashActivity.kt
@@ -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() {
diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt
index 359578f9ea545250a0a12b3bc5d731e258798190..272f24fd15395a3278acdc1818eb48d4914731f5 100644
--- a/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/adapters/BrowseTabsAdapter.kt
@@ -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.*
-
-class BrowseTabsAdapter(val context: Fragment, manager: FragmentManager) : FragmentPagerAdapter(manager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
+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) {
   var tabs = mutableListOf<Fragment>()
 
   override fun getCount() = 5
diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/DownloadsAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/DownloadsAdapter.kt
index c70032835297d11f1f46948fac2227e0e2bb1fe4..17631cb5d593511ec9603b69223fe96723ea4d24 100644
--- a/app/src/main/java/audio/funkwhale/ffa/adapters/DownloadsAdapter.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/adapters/DownloadsAdapter.kt
@@ -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
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt
index 2a840242ff79cc3ec3d6d60c1887d7575716df7b..66ea97a11736d69bb5eed8b39960c3b51435a05c 100644
--- a/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/adapters/FavoritesAdapter.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/PlaylistTracksAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/PlaylistTracksAdapter.kt
index 734e85056e76b79929af163215f0a90117c47d99..70693df12d32ee40bef5b0246735cbd1ba9c551f 100644
--- a/app/src/main/java/audio/funkwhale/ffa/adapters/PlaylistTracksAdapter.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/adapters/PlaylistTracksAdapter.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/RadiosAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/RadiosAdapter.kt
index 12b88b1b0f0f6d81cce5bfe3176d0ae11d6fc2b9..8d57fa2ae490a3592e06e850d0ef19f448cdacb7 100644
--- a/app/src/main/java/audio/funkwhale/ffa/adapters/RadiosAdapter.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/adapters/RadiosAdapter.kt
@@ -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)
           }
         }
       }
diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/SearchAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/SearchAdapter.kt
index df860b92f524161c2416fa3b53cde8ae6dacbc93..f5b2b97b663656841fdae1ea6ef76598757d7e90 100644
--- a/app/src/main/java/audio/funkwhale/ffa/adapters/SearchAdapter.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/adapters/SearchAdapter.kt
@@ -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))
-              }
+            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)
+            rowTrackViewHolder?.favorite?.setOnClickListener {
+              favoriteListener?.let {
+                favoriteListener.onToggleFavorite(track.id, !track.favorite)
 
-                  tracks[position - artists.size - albums.size - sectionCount].favorite =
-                    !track.favorite
+                tracks[position - artists.size - albums.size - sectionCount].favorite =
+                  !track.favorite
 
-                  notifyItemChanged(position)
-                }
+                notifyItemChanged(position)
               }
+            }
 
-              when (track.cached || track.downloaded) {
-                true -> rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
-                  R.drawable.downloaded, 0, 0, 0
-                )
-                false -> rowTrackViewHolder?.title?.setCompoundDrawablesWithIntrinsicBounds(
-                  0, 0, 0, 0
-                )
-              }
+            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)
-                }
+            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)
-                }
+            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
+            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))
                   }
 
-                  show()
+                  true
                 }
+
+                show()
               }
             }
           }
         }
+      }
     }
   }
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/adapters/TracksAdapter.kt b/app/src/main/java/audio/funkwhale/ffa/adapters/TracksAdapter.kt
index c661460a569b591cf01791996c0f3d19137d0d47..049df34d93586ca16ee616e11c0b6bc43e354e7f 100644
--- a/app/src/main/java/audio/funkwhale/ffa/adapters/TracksAdapter.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/adapters/TracksAdapter.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/AddToPlaylistDialog.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/AddToPlaylistDialog.kt
index 4498e5d6898f4ba592648e8cd18d75949c35c31b..2c01cbb867c03004861b803e095185ffc17e9877 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/AddToPlaylistDialog.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/AddToPlaylistDialog.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsFragment.kt
index a6a2116f60c6d02cfa3bf507b1eda8663fcbb04d..c671179f2631ec814fd36226ddb9efb9a3645a29 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsFragment.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsGridFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsGridFragment.kt
index 263ad64f22582221b250887b35f09ff04b707d2d..4259e8834a7e34303f0ea17270ac5c08e2883042 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsGridFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/AlbumsGridFragment.kt
@@ -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>() {
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt
index e79faaa2bf59a1465b8d9e499c4b31560cb5caee..c2c1840e0707e340149155f4d4c888d94abb7396 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/FFAFragment.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt
index 1a4d27fddd339053a0b9b14fd3ca0d4f84edc0f6..38d65fcc446e6b882c34c8540354cbcad8cbdef6 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/FavoritesFragment.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistTracksFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistTracksFragment.kt
index 5e26b81c8e7c621d6587ae9cc62ab54839260216..1b3ac646dd309a4bce12feb16b3af47f4f89258c 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistTracksFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistTracksFragment.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistsFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistsFragment.kt
index 83875c57e86c416029f460bcc3a061bce5114fd9..25cff0d2291d049978e99127417fe2f3e89aadca 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistsFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/PlaylistsFragment.kt
@@ -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>() {
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/RadiosFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/RadiosFragment.kt
index d57d6258a462185c49084d01219285115626eef3..cf9c7640122401e6d4252386366b4e54970669fb 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/RadiosFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/RadiosFragment.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/fragments/TracksFragment.kt b/app/src/main/java/audio/funkwhale/ffa/fragments/TracksFragment.kt
index ce64521d177b83d1d1e4d47b753ddd222d6f4b0b..c8be2af636027d6ad9fecd719ba7e18c11e859ca 100644
--- a/app/src/main/java/audio/funkwhale/ffa/fragments/TracksFragment.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/fragments/TracksFragment.kt
@@ -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))
               }
diff --git a/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt b/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt
index 3f9c3de5e64f8e9f0c9d47bbec794bcdbceefd54..d06ac33e20d427670b8c8e0181ef76deedf62a11 100644
--- a/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/koin/Modules.kt
@@ -64,4 +64,4 @@ fun exoplayerModule(context: Context) = module {
 fun authModule() = module {
   single { OAuth(get()) }
   single { AuthorizationServiceFactory() }
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/AlbumsResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/AlbumsResponse.kt
index 98aa991bfa81264950d4b7bacb5835fe88f5c34b..8f3203f1df14678d8c68100fdeba66e818877726 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/AlbumsResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/AlbumsResponse.kt
@@ -6,4 +6,4 @@ data class AlbumsResponse(
   val results: AlbumList
 ) : FFAResponse<Album>() {
   override fun getData() = results
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/Artist.kt b/app/src/main/java/audio/funkwhale/ffa/model/Artist.kt
index 2a74b6d8ad1605112341b4b97ba0154295f183c0..7e779a7c83ffb769427e9f31790e264228f3f5c5 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/Artist.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/Artist.kt
@@ -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"
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/ArtistsResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/ArtistsResponse.kt
index d59b793e7b01ff6d0dbbb9215cdfa1052fe94418..c504700c94117fffb4dddc1ae7e19865584d3315 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/ArtistsResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/ArtistsResponse.kt
@@ -6,4 +6,4 @@ data class ArtistsResponse(
   val results: List<Artist>
 ) : FFAResponse<Artist>() {
   override fun getData() = results
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt b/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt
index 616bb87aef25cd4e7bf0094cb68331117519e2cc..a1296dbdab7cc4449f6e5842310c4211ea6d05f1 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/CacheItem.kt
@@ -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)
\ No newline at end of file
+class QueueCache(data: List<Track>) : CacheItem<Track>(data)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/CoverUrls.kt b/app/src/main/java/audio/funkwhale/ffa/model/CoverUrls.kt
index 6c935becc5a805f585693f31dea08e65a1210538..8efb18cb8832106108611b7c068744758efbe99f 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/CoverUrls.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/CoverUrls.kt
@@ -1,3 +1,3 @@
 package audio.funkwhale.ffa.model
 
-data class CoverUrls(val original: String)
\ No newline at end of file
+data class CoverUrls(val original: String)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/Covers.kt b/app/src/main/java/audio/funkwhale/ffa/model/Covers.kt
index 86b98803395ca762627e8ec7d72e871dc525542d..52717788343fd92a917943acacd1ae930924a0b8 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/Covers.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/Covers.kt
@@ -1,3 +1,3 @@
 package audio.funkwhale.ffa.model
 
-data class Covers(val urls: CoverUrls)
\ No newline at end of file
+data class Covers(val urls: CoverUrls)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/DownloadInfo.kt b/app/src/main/java/audio/funkwhale/ffa/model/DownloadInfo.kt
index 47d5e0a18019780a2441059ee0d21714d8267d32..383f2ea095718b7baa2dae6227865c633b08e5d1 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/DownloadInfo.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/DownloadInfo.kt
@@ -8,4 +8,4 @@ data class DownloadInfo(
   val title: String,
   val artist: String,
   var download: Download?
-)
\ No newline at end of file
+)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/FFAResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/FFAResponse.kt
index 289fa29097eff07f330f8d09aafeb34a21758ca8..781e50cf24520db4f3b5860bbec0c04431cdd6bf 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/FFAResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/FFAResponse.kt
@@ -5,4 +5,4 @@ abstract class FFAResponse<D : Any> {
   abstract val next: String?
 
   abstract fun getData(): List<D>
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/Favorited.kt b/app/src/main/java/audio/funkwhale/ffa/model/Favorited.kt
index facfd2f1a979107dfd1415883fe40358b7589097..33d02bc96ca7cab0c8b69c5e880673f58e327be8 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/Favorited.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/Favorited.kt
@@ -1,3 +1,3 @@
 package audio.funkwhale.ffa.model
 
-data class Favorited(val track: Int)
\ No newline at end of file
+data class Favorited(val track: Int)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/FavoritedResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/FavoritedResponse.kt
index ab8ae623b52d6be31265cb1fc413bfd0b39c5418..75588b5a01e92ee360ee45a7eb4dcd39bde53732 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/FavoritedResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/FavoritedResponse.kt
@@ -6,4 +6,4 @@ data class FavoritedResponse(
   val results: List<Favorited>
 ) : FFAResponse<Int>() {
   override fun getData() = results.map { it.track }
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/Playlist.kt b/app/src/main/java/audio/funkwhale/ffa/model/Playlist.kt
index 7bf432ad0ecf698b78d9594cfcf9d3366ba7d73a..725a3ba22d88b51f47359f83924e3c0374bf5c2c 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/Playlist.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/Playlist.kt
@@ -6,4 +6,4 @@ data class Playlist(
   val album_covers: List<String>,
   val tracks_count: Int,
   val duration: Int
-)
\ No newline at end of file
+)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTrack.kt b/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTrack.kt
index 4948f57ba7aa2bd6a23c64efcce46e6dc0ba53c0..f1db14b7078b764d71fcc8e888ad21c81fde1b41 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTrack.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTrack.kt
@@ -1,3 +1,3 @@
 package audio.funkwhale.ffa.model
 
-data class PlaylistTrack(val track: Track)
\ No newline at end of file
+data class PlaylistTrack(val track: Track)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTracksResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTracksResponse.kt
index ecfddaeba77b337872858e252bc78171de7ced1f..e3d7e57049d902ace3b4c0ed21c2da8ec13f5c0f 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTracksResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/PlaylistTracksResponse.kt
@@ -6,4 +6,4 @@ data class PlaylistTracksResponse(
   val results: List<PlaylistTrack>
 ) : FFAResponse<PlaylistTrack>() {
   override fun getData() = results
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/PlaylistsResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/PlaylistsResponse.kt
index 623ddb267ef2a1f7c31d8f56c930c026e67458ba..6ccc766fecd4f2ec0f4ee938fe7051107feea7ab 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/PlaylistsResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/PlaylistsResponse.kt
@@ -6,4 +6,4 @@ data class PlaylistsResponse(
   val results: List<Playlist>
 ) : FFAResponse<Playlist>() {
   override fun getData() = results
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/Radio.kt b/app/src/main/java/audio/funkwhale/ffa/model/Radio.kt
index b8d71355af546a6035cbabe55bd4e2a2b42d157d..a23230ba19dda166a27217011dfd980ddba9413e 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/Radio.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/Radio.kt
@@ -6,4 +6,4 @@ data class Radio(
   val name: String,
   val description: String,
   var related_object_id: String? = null
-)
\ No newline at end of file
+)
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/RadiosResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/RadiosResponse.kt
index f2f6d9e989d6333e25f28f73174e959138df8361..b1935b5fb4f96c8abe7293342779ece7db466487 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/RadiosResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/RadiosResponse.kt
@@ -6,4 +6,4 @@ data class RadiosResponse(
   val results: List<Radio>
 ) : FFAResponse<Radio>() {
   override fun getData() = results
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/SearchResult.kt b/app/src/main/java/audio/funkwhale/ffa/model/SearchResult.kt
index e5125763b60ede8eb3b804408f82391a72659ecc..16c49513be8da5a5a2480add1e906068013f6bbe 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/SearchResult.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/SearchResult.kt
@@ -4,4 +4,4 @@ interface SearchResult {
   fun cover(): String?
   fun title(): String
   fun subtitle(): String
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/Track.kt b/app/src/main/java/audio/funkwhale/ffa/model/Track.kt
index a7ea22804f2c1a2a2cc2628571fa0dc8d31183df..e29761e1aa45213841df7d44eababc473e7e0167 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/Track.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/Track.kt
@@ -61,4 +61,4 @@ data class Track(
   override fun subtitle() = artist.name
 
   val formatted: String get() = "$id $artist ($album): $title"
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/model/TracksResponse.kt b/app/src/main/java/audio/funkwhale/ffa/model/TracksResponse.kt
index 21cc942a579ad7924312430410e99e7afe798142..c13026d1c5bc768fdf818138591927dd3be217ac 100644
--- a/app/src/main/java/audio/funkwhale/ffa/model/TracksResponse.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/model/TracksResponse.kt
@@ -6,4 +6,4 @@ data class TracksResponse(
   val results: List<Track>
 ) : FFAResponse<Track>() {
   override fun getData() = results
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/CacheDataSourceFactoryProvider.kt b/app/src/main/java/audio/funkwhale/ffa/playback/CacheDataSourceFactoryProvider.kt
index 8dd33ec15855aa43b31568a25c10957e97e7609d..bc99b0652395e7507e0ba18444a5f50fdf645b65 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/CacheDataSourceFactoryProvider.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/CacheDataSourceFactoryProvider.kt
@@ -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
     }
   }
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt b/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt
index 7fe2a5b7fd318e4ca8f8585cb48188f83824411e..36b5302f6834fd7c82fd36865fe46ef649b697b0 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/MediaControlsManager.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt b/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt
index 34ce450d1419403e26762c4125f0c856a08b6952..9b3a4eba86a3f4e91daadc784240c33f5b174e8c 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/MediaSession.kt
@@ -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
         }
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/OAuth2Datasource.kt b/app/src/main/java/audio/funkwhale/ffa/playback/OAuth2Datasource.kt
index e53f0ddc2b66aa3e83555282edd9e0ff80a0b813..c2aecbc592827bcd56dfa95a7a15bc5f6e54a5cf 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/OAuth2Datasource.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/OAuth2Datasource.kt
@@ -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 {
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt b/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt
index 587c7c132bc9bc6a0ec43d078f78ed5ad46bd89e..fd91becfe571bff8f5364aa46e1ff280a7d4370d 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/PinService.kt
@@ -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) {
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt
index 3731c1b45628cde243e495798c296a2fe8e96bea..ab8b55663dc3045a0c0a25fd88c25643bb17daaf 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/PlayerService.kt
@@ -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()) {
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt b/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt
index f7167010389ec54ef8743a47d07f23c9bf2fe75c..211928dbd6773a77c8c73128e1b59efe75ab22ef 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/QueueManager.kt
@@ -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))
+          }
+        )
       }
     }
 
diff --git a/app/src/main/java/audio/funkwhale/ffa/playback/RadioPlayer.kt b/app/src/main/java/audio/funkwhale/ffa/playback/RadioPlayer.kt
index 8f299da634bfba28e2ffbae063f745b3fcccb477..b9f3ce458ccd01e1d82bdf1a27dd079392ee6f81 100644
--- a/app/src/main/java/audio/funkwhale/ffa/playback/RadioPlayer.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/playback/RadioPlayer.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt
index ca7a04ddeafc7812124e302cb70859cf7cb555c8..46cc2a23d41ce676696ff23017fd8427d01e2a78 100644
--- a/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/repositories/FavoritesRepository.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt
index bbf71cb6db7fc744e223fef5d986ec88fb8181de..8f44802f381c13f0aca241e2802503c94b4da392 100644
--- a/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/PlaylistsRepository.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/PlaylistsRepository.kt
index 752d60f97643ba48c414ffb34ef8c1f60144a44c..daf119a6686705441784b8b59dd40c39a9710491 100644
--- a/app/src/main/java/audio/funkwhale/ffa/repositories/PlaylistsRepository.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/repositories/PlaylistsRepository.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/Repository.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/Repository.kt
index bef2f27d50588fef76b165bc24ece9303fe94140..6ff56dd7d421fff0adf44682a444ab93631da12d 100644
--- a/app/src/main/java/audio/funkwhale/ffa/repositories/Repository.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/repositories/Repository.kt
@@ -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 ->
diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt
index cd27c73a9c31461ff78cba5581c07b98d7396387..e473c426029eee3fd6f18594144150afdb306561 100644
--- a/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/repositories/SearchRepository.kt
@@ -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
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt
index 70d5d11c57f2c2c424c31423f9d3eed3f5c90356..0a250a528c2f6b6e6efcd3151cbd7c1d2917a6ad 100644
--- a/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt
@@ -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)
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/FuelResult.kt b/app/src/main/java/audio/funkwhale/ffa/utils/FuelResult.kt
index 3429eb1810eb3fe69b4c014afdca70424ffcd0e2..db74aac85f16b14dd08c172b0de4f09e5e795511 100644
--- a/app/src/main/java/audio/funkwhale/ffa/utils/FuelResult.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/FuelResult.kt
@@ -19,4 +19,4 @@ data class FuelResult(val httpStatus: Int? = null, val message: String? = null)
       return FuelResult()
     }
   }
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt b/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt
index c0c7c79cc59f5795e93cd8d75d5df63b3100c9c7..5164358ed4cf105b08f8859cb03b055470f025f5 100644
--- a/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt
@@ -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()")
     }
   }
diff --git a/app/src/test/java/audio/funkwhale/ffa/FFATest.kt b/app/src/test/java/audio/funkwhale/ffa/FFATest.kt
index f6d87862edf6426377c2f83341afb5c69b47be41..071342ed5c0e3a4c9f5a2179b513ec22dbc3bb6e 100644
--- a/app/src/test/java/audio/funkwhale/ffa/FFATest.kt
+++ b/app/src/test/java/audio/funkwhale/ffa/FFATest.kt
@@ -58,4 +58,4 @@ class FFATest {
 
     expectThat(picassoCache.exists()).isFalse()
   }
-}
\ No newline at end of file
+}
diff --git a/app/src/test/java/audio/funkwhale/ffa/KoinTestApp.kt b/app/src/test/java/audio/funkwhale/ffa/KoinTestApp.kt
index 1acf92707c2e2712bed2d980a90b330ca211b6d6..a1dae1006cef4d251c45b9105324bdd05e2308d9 100644
--- a/app/src/test/java/audio/funkwhale/ffa/KoinTestApp.kt
+++ b/app/src/test/java/audio/funkwhale/ffa/KoinTestApp.kt
@@ -24,4 +24,4 @@ class KoinTestApp : Application() {
     block()
     unloadKoinModules(module)
   }
-}
\ No newline at end of file
+}
diff --git a/app/src/test/java/audio/funkwhale/ffa/activities/SplashActivityTest.kt b/app/src/test/java/audio/funkwhale/ffa/activities/SplashActivityTest.kt
index 868a4cde561a181f70ae058a6a39d7024b6c2759..2864d6cef9437884c3cada80be087e8571a6f8cc 100644
--- a/app/src/test/java/audio/funkwhale/ffa/activities/SplashActivityTest.kt
+++ b/app/src/test/java/audio/funkwhale/ffa/activities/SplashActivityTest.kt
@@ -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