2021-07-12 10:14:26 +02:00
|
|
|
package audio.funkwhale.ffa.activities
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
import android.animation.Animator
|
|
|
|
import android.animation.AnimatorListenerAdapter
|
2019-10-24 12:35:34 +02:00
|
|
|
import android.animation.ObjectAnimator
|
2019-08-19 16:50:33 +02:00
|
|
|
import android.annotation.SuppressLint
|
|
|
|
import android.content.Intent
|
2019-11-05 21:23:29 +01:00
|
|
|
import android.graphics.Bitmap
|
2020-07-10 17:18:29 +02:00
|
|
|
import android.os.Build
|
2019-08-19 16:50:33 +02:00
|
|
|
import android.os.Bundle
|
2019-11-05 21:23:29 +01:00
|
|
|
import android.util.DisplayMetrics
|
2021-09-09 09:56:15 +02:00
|
|
|
import android.view.Gravity
|
|
|
|
import android.view.Menu
|
|
|
|
import android.view.MenuItem
|
|
|
|
import android.view.View
|
|
|
|
import android.view.ViewGroup
|
2019-10-24 12:35:34 +02:00
|
|
|
import android.view.animation.AccelerateDecelerateInterpolator
|
2019-08-19 16:50:33 +02:00
|
|
|
import android.widget.SeekBar
|
2023-01-10 13:56:20 +01:00
|
|
|
import androidx.activity.addCallback
|
2022-08-27 09:05:38 +02:00
|
|
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
|
2019-08-19 16:50:33 +02:00
|
|
|
import androidx.appcompat.app.AppCompatActivity
|
2023-01-10 13:56:20 +01:00
|
|
|
import androidx.appcompat.content.res.AppCompatResources
|
2020-05-29 21:40:01 +02:00
|
|
|
import androidx.appcompat.widget.PopupMenu
|
2020-05-29 23:42:03 +02:00
|
|
|
import androidx.core.content.ContextCompat
|
2019-11-05 21:23:29 +01:00
|
|
|
import androidx.core.graphics.drawable.toDrawable
|
2019-08-19 16:50:33 +02:00
|
|
|
import androidx.fragment.app.DialogFragment
|
2020-09-04 16:56:31 +02:00
|
|
|
import androidx.lifecycle.Lifecycle
|
2020-06-25 01:26:15 +02:00
|
|
|
import androidx.lifecycle.lifecycleScope
|
2023-01-10 13:56:20 +01:00
|
|
|
import androidx.navigation.NavController
|
|
|
|
import androidx.navigation.fragment.NavHostFragment
|
2021-07-21 09:11:07 +02:00
|
|
|
import audio.funkwhale.ffa.FFA
|
2021-07-16 10:03:52 +02:00
|
|
|
import audio.funkwhale.ffa.R
|
|
|
|
import audio.funkwhale.ffa.databinding.ActivityMainBinding
|
2021-09-09 09:56:15 +02:00
|
|
|
import audio.funkwhale.ffa.fragments.AddToPlaylistDialog
|
2023-01-10 13:56:20 +01:00
|
|
|
import audio.funkwhale.ffa.fragments.BrowseFragmentDirections
|
2021-09-09 09:56:15 +02:00
|
|
|
import audio.funkwhale.ffa.fragments.LandscapeQueueFragment
|
|
|
|
import audio.funkwhale.ffa.fragments.QueueFragment
|
|
|
|
import audio.funkwhale.ffa.fragments.TrackInfoDetailsFragment
|
2021-08-22 09:48:33 +02:00
|
|
|
import audio.funkwhale.ffa.model.Track
|
2021-07-16 10:03:52 +02:00
|
|
|
import audio.funkwhale.ffa.playback.MediaControlsManager
|
|
|
|
import audio.funkwhale.ffa.playback.PinService
|
|
|
|
import audio.funkwhale.ffa.playback.PlayerService
|
|
|
|
import audio.funkwhale.ffa.repositories.FavoritedRepository
|
|
|
|
import audio.funkwhale.ffa.repositories.FavoritesRepository
|
|
|
|
import audio.funkwhale.ffa.repositories.Repository
|
2021-09-09 09:56:15 +02:00
|
|
|
import audio.funkwhale.ffa.utils.AppContext
|
|
|
|
import audio.funkwhale.ffa.utils.Command
|
|
|
|
import audio.funkwhale.ffa.utils.CommandBus
|
2023-01-10 11:00:41 +01:00
|
|
|
import audio.funkwhale.ffa.utils.CoverArt
|
2021-09-09 09:56:15 +02:00
|
|
|
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.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
|
2021-07-16 10:03:52 +02:00
|
|
|
import audio.funkwhale.ffa.views.DisableableFrameLayout
|
2020-06-01 16:31:58 +02:00
|
|
|
import com.github.kittinunf.fuel.Fuel
|
|
|
|
import com.github.kittinunf.fuel.coroutines.awaitStringResponse
|
2020-05-29 23:42:03 +02:00
|
|
|
import com.google.android.exoplayer2.Player
|
2020-06-13 16:09:48 +02:00
|
|
|
import com.google.android.exoplayer2.offline.DownloadService
|
2020-06-01 16:31:58 +02:00
|
|
|
import com.google.gson.Gson
|
2019-08-19 16:50:33 +02:00
|
|
|
import com.preference.PowerPreference
|
2020-06-14 00:42:45 +02:00
|
|
|
import jp.wasabeef.picasso.transformations.RoundedCornersTransformation
|
2020-06-25 01:26:15 +02:00
|
|
|
import kotlinx.coroutines.Dispatchers.Default
|
2019-08-19 16:50:33 +02:00
|
|
|
import kotlinx.coroutines.Dispatchers.IO
|
|
|
|
import kotlinx.coroutines.Dispatchers.Main
|
|
|
|
import kotlinx.coroutines.launch
|
2019-11-05 21:23:29 +01:00
|
|
|
import kotlinx.coroutines.withContext
|
2021-08-09 06:50:46 +02:00
|
|
|
import org.koin.java.KoinJavaComponent.inject
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
class MainActivity : AppCompatActivity() {
|
2019-10-23 20:21:18 +02:00
|
|
|
enum class ResultCode(val code: Int) {
|
|
|
|
LOGOUT(1001)
|
|
|
|
}
|
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
private val favoriteRepository = FavoritesRepository(this)
|
2020-07-11 16:56:09 +02:00
|
|
|
private val favoritedRepository = FavoritedRepository(this)
|
2020-09-03 12:09:56 +02:00
|
|
|
private var menu: Menu? = null
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
private lateinit var binding: ActivityMainBinding
|
2021-08-09 06:50:46 +02:00
|
|
|
private val oAuth: OAuth by inject(OAuth::class.java)
|
2021-07-16 10:03:52 +02:00
|
|
|
|
2023-01-10 13:56:20 +01:00
|
|
|
private val navigation: NavController by lazy {
|
|
|
|
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
|
|
|
|
navHost.navController
|
|
|
|
}
|
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
|
|
super.onCreate(savedInstanceState)
|
|
|
|
AppContext.init(this)
|
2021-07-16 10:03:52 +02:00
|
|
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
|
|
|
|
|
|
|
setContentView(binding.root)
|
|
|
|
|
|
|
|
setSupportActionBar(binding.appbar)
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2023-01-10 13:56:20 +01:00
|
|
|
onBackPressedDispatcher.addCallback(this) {
|
|
|
|
if (binding.nowPlaying.isOpened()) {
|
|
|
|
binding.nowPlaying.close()
|
|
|
|
} else {
|
|
|
|
navigation.navigateUp()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
when (intent.action) {
|
|
|
|
MediaControlsManager.NOTIFICATION_ACTION_OPEN_QUEUE.toString() -> launchDialog(QueueFragment())
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:26:15 +02:00
|
|
|
watchEventBus()
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
override fun onResume() {
|
|
|
|
super.onResume()
|
|
|
|
|
2023-01-10 13:56:20 +01:00
|
|
|
findViewById<DisableableFrameLayout?>(R.id.container)?.apply {
|
|
|
|
setShouldRegisterTouch {
|
|
|
|
if (binding.nowPlaying.isOpened()) {
|
|
|
|
binding.nowPlaying.close()
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
2020-07-12 18:55:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-11 16:56:09 +02:00
|
|
|
favoritedRepository.update(this, lifecycleScope)
|
2020-07-10 15:08:08 +02:00
|
|
|
|
2019-10-31 00:46:35 +01:00
|
|
|
startService(Intent(this, PlayerService::class.java))
|
2020-06-13 16:09:48 +02:00
|
|
|
DownloadService.start(this, PinService::class.java)
|
2019-10-31 00:46:35 +01:00
|
|
|
|
2020-06-25 01:26:15 +02:00
|
|
|
CommandBus.send(Command.RefreshService)
|
|
|
|
|
|
|
|
lifecycleScope.launch(IO) {
|
2021-08-09 06:50:46 +02:00
|
|
|
Userinfo.get(this@MainActivity, oAuth)
|
2020-06-21 13:36:42 +02:00
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
with(binding) {
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
nowPlayingContainer?.nowPlayingToggle?.setOnClickListener {
|
|
|
|
CommandBus.send(Command.ToggleState)
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
nowPlayingContainer?.nowPlayingNext?.setOnClickListener {
|
|
|
|
CommandBus.send(Command.NextTrack)
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
nowPlayingContainer?.nowPlayingDetailsPrevious?.setOnClickListener {
|
|
|
|
CommandBus.send(Command.PreviousTrack)
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
nowPlayingContainer?.nowPlayingDetailsNext?.setOnClickListener {
|
|
|
|
CommandBus.send(Command.NextTrack)
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
nowPlayingContainer?.nowPlayingDetailsToggle?.setOnClickListener {
|
|
|
|
CommandBus.send(Command.ToggleState)
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2022-08-25 14:58:19 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsProgress?.setOnSeekBarChangeListener(
|
|
|
|
object : SeekBar.OnSeekBarChangeListener {
|
|
|
|
override fun onStopTrackingTouch(view: SeekBar?) {}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2022-08-25 14:58:19 +02:00
|
|
|
override fun onStartTrackingTouch(view: SeekBar?) {}
|
2021-07-16 10:03:52 +02:00
|
|
|
|
2022-08-25 14:58:19 +02:00
|
|
|
override fun onProgressChanged(view: SeekBar?, progress: Int, fromUser: Boolean) {
|
|
|
|
if (fromUser) {
|
|
|
|
CommandBus.send(Command.Seek(progress))
|
|
|
|
}
|
2021-07-16 10:03:52 +02:00
|
|
|
}
|
2022-08-25 14:58:19 +02:00
|
|
|
})
|
2019-11-05 21:23:29 +01:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
landscapeQueue?.let {
|
|
|
|
supportFragmentManager.beginTransaction()
|
|
|
|
.replace(R.id.landscape_queue, LandscapeQueueFragment()).commit()
|
|
|
|
}
|
2019-11-05 21:23:29 +01:00
|
|
|
}
|
2020-06-20 15:42:10 +02:00
|
|
|
}
|
|
|
|
|
2022-12-08 10:23:58 +01:00
|
|
|
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
2020-09-03 12:09:56 +02:00
|
|
|
this.menu = menu
|
|
|
|
|
|
|
|
return super.onPrepareOptionsMenu(menu)
|
|
|
|
}
|
|
|
|
|
2022-12-07 12:00:49 +01:00
|
|
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
2019-08-19 16:50:33 +02:00
|
|
|
menuInflater.inflate(R.menu.toolbar, menu)
|
|
|
|
|
2022-12-07 12:00:49 +01:00
|
|
|
menu.findItem(R.id.nav_all_music)?.let {
|
2020-09-03 22:53:06 +02:00
|
|
|
it.isChecked = Settings.getScopes().contains("all")
|
|
|
|
it.isEnabled = !it.isChecked
|
|
|
|
}
|
|
|
|
|
2022-12-07 12:00:49 +01:00
|
|
|
menu.findItem(R.id.nav_my_music)?.isChecked = Settings.getScopes().contains("me")
|
|
|
|
menu.findItem(R.id.nav_followed)?.isChecked = Settings.getScopes().contains("subscribed")
|
2020-06-13 18:34:28 +02:00
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2022-08-27 09:05:38 +02:00
|
|
|
var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
|
|
|
|
if (result.resultCode == ResultCode.LOGOUT.code) {
|
|
|
|
Intent(this, LoginActivity::class.java).apply {
|
|
|
|
FFA.get().deleteAllData(this@MainActivity)
|
|
|
|
|
|
|
|
flags =
|
|
|
|
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
|
|
|
|
|
|
|
stopService(Intent(this@MainActivity, PlayerService::class.java))
|
|
|
|
startActivity(this)
|
|
|
|
finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-19 16:50:33 +02:00
|
|
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
|
|
when (item.itemId) {
|
|
|
|
android.R.id.home -> {
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlaying.close()
|
2023-01-10 13:56:20 +01:00
|
|
|
navigation.popBackStack(R.id.browseFragment, false)
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
R.id.nav_queue -> launchDialog(QueueFragment())
|
2023-01-10 13:56:20 +01:00
|
|
|
R.id.nav_search -> navigation.navigate(BrowseFragmentDirections.browseToSearch())
|
2020-09-03 12:09:56 +02:00
|
|
|
R.id.nav_all_music, R.id.nav_my_music, R.id.nav_followed -> {
|
|
|
|
menu?.let { menu ->
|
|
|
|
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW)
|
|
|
|
item.actionView = View(this)
|
|
|
|
item.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
2022-12-06 09:31:09 +01:00
|
|
|
override fun onMenuItemActionExpand(item: MenuItem) = false
|
|
|
|
override fun onMenuItemActionCollapse(item: MenuItem) = false
|
2020-09-03 12:09:56 +02:00
|
|
|
})
|
2020-06-13 18:34:28 +02:00
|
|
|
|
2020-09-03 12:09:56 +02:00
|
|
|
item.isChecked = !item.isChecked
|
|
|
|
|
|
|
|
val scopes = Settings.getScopes().toMutableSet()
|
|
|
|
|
|
|
|
val new = when (item.itemId) {
|
|
|
|
R.id.nav_my_music -> "me"
|
|
|
|
R.id.nav_followed -> "subscribed"
|
|
|
|
|
|
|
|
else -> {
|
2020-09-03 22:53:06 +02:00
|
|
|
menu.findItem(R.id.nav_all_music).isEnabled = false
|
2020-09-03 12:09:56 +02:00
|
|
|
menu.findItem(R.id.nav_my_music).isChecked = false
|
|
|
|
menu.findItem(R.id.nav_followed).isChecked = false
|
2021-07-01 13:25:09 +02:00
|
|
|
PowerPreference.getDefaultFile().setString("scope", "all")
|
2020-09-03 12:09:56 +02:00
|
|
|
EventBus.send(Event.ListingsChanged)
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-03 22:53:06 +02:00
|
|
|
menu.findItem(R.id.nav_all_music).let {
|
|
|
|
it.isChecked = false
|
|
|
|
it.isEnabled = true
|
|
|
|
}
|
2020-09-03 12:09:56 +02:00
|
|
|
|
|
|
|
scopes.remove("all")
|
|
|
|
|
|
|
|
when (item.isChecked) {
|
|
|
|
true -> scopes.add(new)
|
|
|
|
false -> scopes.remove(new)
|
|
|
|
}
|
|
|
|
|
2020-09-03 22:53:06 +02:00
|
|
|
if (scopes.isEmpty()) {
|
|
|
|
menu.findItem(R.id.nav_all_music).let {
|
|
|
|
it.isChecked = true
|
|
|
|
it.isEnabled = false
|
|
|
|
}
|
|
|
|
|
|
|
|
scopes.add("all")
|
|
|
|
}
|
|
|
|
|
2021-07-01 13:25:09 +02:00
|
|
|
PowerPreference.getDefaultFile().setString("scope", scopes.joinToString(","))
|
2020-09-03 12:09:56 +02:00
|
|
|
EventBus.send(Event.ListingsChanged)
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
2020-06-13 18:34:28 +02:00
|
|
|
}
|
2020-06-13 16:09:48 +02:00
|
|
|
R.id.nav_downloads -> startActivity(Intent(this, DownloadsActivity::class.java))
|
2022-08-27 09:05:38 +02:00
|
|
|
R.id.settings -> resultLauncher.launch(Intent(this, SettingsActivity::class.java))
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-01-10 13:56:20 +01:00
|
|
|
private fun launchDialog(fragment: DialogFragment) =
|
|
|
|
fragment.show(supportFragmentManager.beginTransaction(), "")
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
@SuppressLint("NewApi")
|
|
|
|
private fun watchEventBus() {
|
2020-06-25 01:26:15 +02:00
|
|
|
lifecycleScope.launch(Main) {
|
2022-08-26 14:06:41 +02:00
|
|
|
EventBus.get().collect { event ->
|
|
|
|
if (event is Event.LogOut) {
|
|
|
|
FFA.get().deleteAllData(this@MainActivity)
|
|
|
|
startActivity(
|
|
|
|
Intent(this@MainActivity, LoginActivity::class.java).apply {
|
|
|
|
flags = Intent.FLAG_ACTIVITY_NO_HISTORY
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
2022-08-26 14:06:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
finish()
|
|
|
|
} else if (event is Event.PlaybackError) {
|
|
|
|
toast(event.message)
|
|
|
|
} else if (event is Event.Buffering) {
|
|
|
|
when (event.value) {
|
|
|
|
true -> binding.nowPlayingContainer?.nowPlayingBuffering?.visibility = View.VISIBLE
|
|
|
|
false -> binding.nowPlayingContainer?.nowPlayingBuffering?.visibility = View.GONE
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
2022-08-26 14:06:41 +02:00
|
|
|
} else if (event is Event.PlaybackStopped) {
|
|
|
|
if (binding.nowPlaying.visibility == View.VISIBLE) {
|
2023-01-10 13:56:20 +01:00
|
|
|
(binding.navHostFragment.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
|
2022-08-26 14:06:41 +02:00
|
|
|
it.bottomMargin = it.bottomMargin / 2
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2022-08-26 14:06:41 +02:00
|
|
|
binding.landscapeQueue?.let { landscape_queue ->
|
|
|
|
(landscape_queue.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
|
2019-08-19 16:50:33 +02:00
|
|
|
it.bottomMargin = it.bottomMargin / 2
|
|
|
|
}
|
2022-08-26 14:06:41 +02:00
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2022-08-26 14:06:41 +02:00
|
|
|
binding.nowPlaying.animate()
|
|
|
|
.alpha(0.0f)
|
|
|
|
.setDuration(400)
|
|
|
|
.setListener(object : AnimatorListenerAdapter() {
|
2022-12-06 09:31:09 +01:00
|
|
|
override fun onAnimationEnd(animator: Animator) {
|
2022-08-26 14:06:41 +02:00
|
|
|
binding.nowPlaying.visibility = View.GONE
|
2019-11-05 21:23:29 +01:00
|
|
|
}
|
2022-08-26 14:06:41 +02:00
|
|
|
})
|
|
|
|
.start()
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
2022-08-26 14:06:41 +02:00
|
|
|
} else if (event is Event.TrackFinished) {
|
|
|
|
incrementListenCount(event.track)
|
|
|
|
} else if (event is Event.StateChanged) {
|
|
|
|
when (event.playing) {
|
|
|
|
true -> {
|
2023-01-10 13:56:20 +01:00
|
|
|
binding.nowPlayingContainer?.nowPlayingToggle?.icon =
|
|
|
|
AppCompatResources.getDrawable(this@MainActivity, R.drawable.pause)
|
2022-08-26 14:06:41 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsToggle?.icon =
|
2023-01-10 13:56:20 +01:00
|
|
|
AppCompatResources.getDrawable(this@MainActivity, R.drawable.pause)
|
2022-08-26 14:06:41 +02:00
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
|
2022-08-26 14:06:41 +02:00
|
|
|
false -> {
|
2023-01-10 13:56:20 +01:00
|
|
|
binding.nowPlayingContainer?.nowPlayingToggle?.icon =
|
|
|
|
AppCompatResources.getDrawable(this@MainActivity, R.drawable.play)
|
2022-08-26 14:06:41 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsToggle?.icon =
|
2023-01-10 13:56:20 +01:00
|
|
|
AppCompatResources.getDrawable(this@MainActivity, R.drawable.play)
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
}
|
2022-08-26 14:06:41 +02:00
|
|
|
} else if (event is Event.QueueChanged) {
|
|
|
|
findViewById<View>(R.id.nav_queue)?.let { view ->
|
|
|
|
ObjectAnimator.ofFloat(view, View.ROTATION, 0f, 360f).let {
|
|
|
|
it.duration = 500
|
|
|
|
it.interpolator = AccelerateDecelerateInterpolator()
|
|
|
|
it.start()
|
2019-10-24 12:35:34 +02:00
|
|
|
}
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:26:15 +02:00
|
|
|
lifecycleScope.launch(Main) {
|
2020-06-24 14:54:13 +02:00
|
|
|
CommandBus.get().collect { command ->
|
2022-08-26 14:06:41 +02:00
|
|
|
if (command is Command.StartService) {
|
|
|
|
Build.VERSION_CODES.O.onApi(
|
|
|
|
{
|
|
|
|
startForegroundService(
|
|
|
|
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())
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
)
|
|
|
|
} else if (command is Command.RefreshTrack) {
|
|
|
|
refreshCurrentTrack(command.track)
|
|
|
|
} else if (command is Command.AddToPlaylist) {
|
|
|
|
if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
2021-07-16 10:03:52 +02:00
|
|
|
AddToPlaylistDialog.show(
|
|
|
|
layoutInflater,
|
|
|
|
this@MainActivity,
|
|
|
|
lifecycleScope,
|
|
|
|
command.tracks
|
|
|
|
)
|
2021-07-01 13:25:09 +02:00
|
|
|
}
|
2020-06-24 14:54:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:26:15 +02:00
|
|
|
lifecycleScope.launch(Main) {
|
2019-10-31 16:17:37 +01:00
|
|
|
ProgressBus.get().collect { (current, duration, percent) ->
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingProgress?.progress = percent
|
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsProgress?.progress = percent
|
2019-08-19 16:50:33 +02:00
|
|
|
|
|
|
|
val currentMins = (current / 1000) / 60
|
|
|
|
val currentSecs = (current / 1000) % 60
|
|
|
|
|
|
|
|
val durationMins = duration / 60
|
|
|
|
val durationSecs = duration % 60
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsProgressCurrent?.text =
|
|
|
|
"%02d:%02d".format(currentMins, currentSecs)
|
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsProgressDuration?.text =
|
|
|
|
"%02d:%02d".format(durationMins, durationSecs)
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-29 23:42:03 +02:00
|
|
|
|
2020-06-01 16:31:58 +02:00
|
|
|
private fun refreshCurrentTrack(track: Track?) {
|
2020-06-01 21:25:16 +02:00
|
|
|
track?.let {
|
2021-07-16 10:03:52 +02:00
|
|
|
if (binding.nowPlaying.visibility == View.GONE) {
|
|
|
|
binding.nowPlaying.visibility = View.VISIBLE
|
|
|
|
binding.nowPlaying.alpha = 0f
|
2020-06-01 16:31:58 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlaying.animate()
|
2020-06-01 16:31:58 +02:00
|
|
|
.alpha(1.0f)
|
|
|
|
.setDuration(400)
|
|
|
|
.setListener(null)
|
|
|
|
.start()
|
|
|
|
|
2023-01-11 13:41:04 +01:00
|
|
|
(binding.navHostFragment.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
|
2020-06-01 16:31:58 +02:00
|
|
|
it.bottomMargin = it.bottomMargin * 2
|
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.landscapeQueue?.let { landscape_queue ->
|
2020-06-01 16:31:58 +02:00
|
|
|
(landscape_queue.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
|
|
|
|
it.bottomMargin = it.bottomMargin * 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingTitle?.text = track.title
|
|
|
|
binding.nowPlayingContainer?.nowPlayingAlbum?.text = track.artist.name
|
2020-06-01 16:31:58 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsTitle?.text = track.title
|
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsArtist?.text = track.artist.name
|
2020-06-01 16:31:58 +02:00
|
|
|
|
2023-01-10 11:00:41 +01:00
|
|
|
val lic = this.layoutInflater.context
|
|
|
|
|
2023-01-11 13:41:04 +01:00
|
|
|
CoverArt.withContext(lic, maybeNormalizeUrl(track.cover()))
|
2020-06-01 16:31:58 +02:00
|
|
|
.fit()
|
|
|
|
.centerCrop()
|
2021-07-16 10:03:52 +02:00
|
|
|
.into(binding.nowPlayingContainer?.nowPlayingCover)
|
2020-06-01 16:31:58 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsCover?.let { nowPlayingDetailsCover ->
|
2023-01-11 13:41:04 +01:00
|
|
|
CoverArt.withContext(lic, maybeNormalizeUrl(track.cover()))
|
2020-06-01 16:31:58 +02:00
|
|
|
.fit()
|
|
|
|
.centerCrop()
|
2020-06-14 00:42:45 +02:00
|
|
|
.transform(RoundedCornersTransformation(16, 0))
|
2021-07-16 10:03:52 +02:00
|
|
|
.into(nowPlayingDetailsCover)
|
2020-06-01 16:31:58 +02:00
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
if (binding.nowPlayingContainer?.nowPlayingCover == null) {
|
2020-06-25 01:26:15 +02:00
|
|
|
lifecycleScope.launch(Default) {
|
2020-06-01 16:31:58 +02:00
|
|
|
val width = DisplayMetrics().apply {
|
|
|
|
windowManager.defaultDisplay.getMetrics(this)
|
|
|
|
}.widthPixels
|
|
|
|
|
2023-01-11 13:41:04 +01:00
|
|
|
val backgroundCover = CoverArt.withContext(lic, maybeNormalizeUrl(track.cover()))
|
2020-06-01 16:31:58 +02:00
|
|
|
.get()
|
|
|
|
.run { Bitmap.createScaledBitmap(this, width, width, false).toDrawable(resources) }
|
|
|
|
.apply {
|
|
|
|
alpha = 20
|
|
|
|
gravity = Gravity.CENTER
|
|
|
|
}
|
|
|
|
|
|
|
|
withContext(Main) {
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetails?.background = backgroundCover
|
2020-06-01 16:31:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.let { now_playing_details_repeat ->
|
2022-06-12 14:48:32 +02:00
|
|
|
changeRepeatMode(FFACache.getLine(this@MainActivity, "repeat")?.toInt() ?: 0)
|
2020-06-01 16:31:58 +02:00
|
|
|
|
|
|
|
now_playing_details_repeat.setOnClickListener {
|
2022-06-12 14:48:32 +02:00
|
|
|
val current = FFACache.getLine(this@MainActivity, "repeat")?.toInt() ?: 0
|
2020-06-01 16:31:58 +02:00
|
|
|
|
|
|
|
changeRepeatMode((current + 1) % 3)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsInfo?.let { nowPlayingDetailsInfo ->
|
|
|
|
nowPlayingDetailsInfo.setOnClickListener {
|
2021-07-01 13:25:09 +02:00
|
|
|
PopupMenu(
|
|
|
|
this@MainActivity,
|
2021-07-16 10:03:52 +02:00
|
|
|
nowPlayingDetailsInfo,
|
2021-07-01 13:25:09 +02:00
|
|
|
Gravity.START,
|
|
|
|
R.attr.actionOverflowMenuStyle,
|
|
|
|
0
|
|
|
|
).apply {
|
2020-06-01 16:31:58 +02:00
|
|
|
inflate(R.menu.track_info)
|
|
|
|
|
|
|
|
setOnMenuItemClickListener {
|
|
|
|
when (it.itemId) {
|
2023-01-10 13:56:20 +01:00
|
|
|
R.id.track_info_artist -> BrowseFragmentDirections.browseToAlbums(
|
2021-07-01 13:25:09 +02:00
|
|
|
track.artist,
|
2023-01-10 13:56:20 +01:00
|
|
|
track.album?.cover()
|
2021-07-01 13:25:09 +02:00
|
|
|
)
|
2023-01-10 13:56:20 +01:00
|
|
|
R.id.track_info_album -> track.album?.let(BrowseFragmentDirections::browseToTracks)
|
2021-07-01 13:25:09 +02:00
|
|
|
R.id.track_info_details -> TrackInfoDetailsFragment.new(track)
|
|
|
|
.show(supportFragmentManager, "dialog")
|
2020-06-01 16:31:58 +02:00
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlaying.close()
|
2020-06-01 16:31:58 +02:00
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
|
|
|
show()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsFavorite?.let { now_playing_details_favorite ->
|
2020-07-11 16:56:09 +02:00
|
|
|
favoritedRepository.fetch().untilNetwork(lifecycleScope, IO) { favorites, _, _, _ ->
|
2020-06-25 01:26:15 +02:00
|
|
|
lifecycleScope.launch(Main) {
|
2020-06-01 16:31:58 +02:00
|
|
|
track.favorite = favorites.contains(track.id)
|
|
|
|
|
|
|
|
when (track.favorite) {
|
|
|
|
true -> now_playing_details_favorite.setColorFilter(getColor(R.color.colorFavorite))
|
|
|
|
false -> now_playing_details_favorite.setColorFilter(getColor(R.color.controlForeground))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
now_playing_details_favorite.setOnClickListener {
|
|
|
|
when (track.favorite) {
|
|
|
|
true -> {
|
|
|
|
favoriteRepository.deleteFavorite(track.id)
|
|
|
|
now_playing_details_favorite.setColorFilter(getColor(R.color.controlForeground))
|
|
|
|
}
|
|
|
|
|
|
|
|
false -> {
|
|
|
|
favoriteRepository.addFavorite(track.id)
|
|
|
|
now_playing_details_favorite.setColorFilter(getColor(R.color.colorFavorite))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
track.favorite = !track.favorite
|
|
|
|
|
|
|
|
favoriteRepository.fetch(Repository.Origin.Network.origin)
|
|
|
|
}
|
2020-09-26 18:34:13 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsAddToPlaylist?.setOnClickListener {
|
2020-09-26 18:34:13 +02:00
|
|
|
CommandBus.send(Command.AddToPlaylist(listOf(track)))
|
|
|
|
}
|
2020-06-01 16:31:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-29 23:42:03 +02:00
|
|
|
private fun changeRepeatMode(index: Int) {
|
|
|
|
when (index) {
|
|
|
|
// From no repeat to repeat all
|
|
|
|
0 -> {
|
2022-06-12 14:48:32 +02:00
|
|
|
FFACache.set(this@MainActivity, "repeat", "0")
|
2020-05-29 23:42:03 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.setImageResource(R.drawable.repeat)
|
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.setColorFilter(
|
2021-07-01 13:25:09 +02:00
|
|
|
ContextCompat.getColor(
|
|
|
|
this,
|
|
|
|
R.color.controlForeground
|
|
|
|
)
|
|
|
|
)
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.alpha = 0.2f
|
2020-05-29 23:42:03 +02:00
|
|
|
|
|
|
|
CommandBus.send(Command.SetRepeatMode(Player.REPEAT_MODE_OFF))
|
|
|
|
}
|
|
|
|
|
|
|
|
// From repeat all to repeat one
|
|
|
|
1 -> {
|
2022-06-12 14:48:32 +02:00
|
|
|
FFACache.set(this@MainActivity, "repeat", "1")
|
2020-05-29 23:42:03 +02:00
|
|
|
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.setImageResource(R.drawable.repeat)
|
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.setColorFilter(
|
2021-07-01 13:25:09 +02:00
|
|
|
ContextCompat.getColor(
|
|
|
|
this,
|
|
|
|
R.color.controlForeground
|
|
|
|
)
|
|
|
|
)
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.alpha = 1.0f
|
2020-05-29 23:42:03 +02:00
|
|
|
|
|
|
|
CommandBus.send(Command.SetRepeatMode(Player.REPEAT_MODE_ALL))
|
|
|
|
}
|
|
|
|
|
|
|
|
// From repeat one to no repeat
|
|
|
|
2 -> {
|
2022-06-12 14:48:32 +02:00
|
|
|
FFACache.set(this@MainActivity, "repeat", "2")
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.setImageResource(R.drawable.repeat_one)
|
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.setColorFilter(
|
2021-07-01 13:25:09 +02:00
|
|
|
ContextCompat.getColor(
|
|
|
|
this,
|
|
|
|
R.color.controlForeground
|
|
|
|
)
|
|
|
|
)
|
2021-07-16 10:03:52 +02:00
|
|
|
binding.nowPlayingContainer?.nowPlayingDetailsRepeat?.alpha = 1.0f
|
2020-05-29 23:42:03 +02:00
|
|
|
|
|
|
|
CommandBus.send(Command.SetRepeatMode(Player.REPEAT_MODE_ONE))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-01 16:31:58 +02:00
|
|
|
|
|
|
|
private fun incrementListenCount(track: Track?) {
|
2020-06-01 21:25:16 +02:00
|
|
|
track?.let {
|
2021-08-07 20:20:48 +02:00
|
|
|
it.log("Incrementing listen count for track ${track.id}")
|
2020-06-25 01:26:15 +02:00
|
|
|
lifecycleScope.launch(IO) {
|
2020-06-20 22:10:13 +02:00
|
|
|
try {
|
|
|
|
Fuel
|
|
|
|
.post(mustNormalizeUrl("/api/v1/history/listenings/"))
|
2021-08-09 06:50:46 +02:00
|
|
|
.authorize(this@MainActivity, oAuth)
|
2020-06-20 22:10:13 +02:00
|
|
|
.header("Content-Type", "application/json")
|
|
|
|
.body(Gson().toJson(mapOf("track" to track.id)))
|
|
|
|
.awaitStringResponse()
|
2021-08-07 20:20:48 +02:00
|
|
|
} catch (e: Exception) {
|
2021-08-13 10:55:26 +02:00
|
|
|
e.logError("incrementListenCount()")
|
2020-06-20 22:10:13 +02:00
|
|
|
}
|
2020-06-01 16:31:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-19 16:50:33 +02:00
|
|
|
}
|