package com.lofiradio.ui import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import coil.load import com.lofiradio.R import com.lofiradio.databinding.FragmentPlayerBinding import com.lofiradio.player.AudioPlayer import com.lofiradio.util.Preferences class PlayerFragment : Fragment() { private var _binding: FragmentPlayerBinding? = null private val binding get() = _binding!! private val viewModel: LofiViewModel by viewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentPlayerBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupControls() observeViewModel() } private fun setupControls() { binding.btnPlayPause.setOnClickListener { when (viewModel.playerState.value) { LofiViewModel.PlayerState.PLAYING -> viewModel.pausePlayback() LofiViewModel.PlayerState.PAUSED -> viewModel.resumePlayback() LofiViewModel.PlayerState.IDLE -> { val channel = viewModel.currentChannel.value if (channel != null) { viewModel.playChannel(channel) } } else -> { val channel = viewModel.currentChannel.value if (channel != null) { viewModel.playChannel(channel) } } } } binding.btnNext.setOnClickListener { viewModel.playNext() } binding.btnPrevious.setOnClickListener { viewModel.playPrevious() } binding.volumeSlider.setOnSeekBarChangeListener(object : android.widget.SeekBar.OnSeekBarChangeListener { override fun onProgressChanged(seekBar: android.widget.SeekBar?, progress: Int, fromUser: Boolean) { if (fromUser) { viewModel.setVolume(progress / 100f) binding.volumeValue.text = "$progress%" } } override fun onStartTrackingTouch(seekBar: android.widget.SeekBar?) {} override fun onStopTrackingTouch(seekBar: android.widget.SeekBar?) {} }) binding.btnRetry.setOnClickListener { viewModel.retry() } } private fun observeViewModel() { viewModel.currentChannel.observe(viewLifecycleOwner) { channel -> channel?.let { binding.playerChannelName.text = it.name binding.playerVideoTitle.text = it.description val thumbUrl = it.liveThumbnail ?: it.thumbnail if (!thumbUrl.isNullOrBlank()) { binding.playerThumbnail.load(thumbUrl) { crossfade(true) } } binding.playerMode.text = when (viewModel.getStreamingMode()) { Preferences.StreamingMode.SERVER -> "Server Mode" Preferences.StreamingMode.DIRECT -> "Direct Mode" } } ?: run { binding.playerChannelName.text = "No Channel Selected" binding.playerVideoTitle.text = "" binding.playerMode.text = "" } } viewModel.playerState.observe(viewLifecycleOwner) { state -> updatePlayerUi(state) } viewModel.isLoading.observe(viewLifecycleOwner) { loading -> if (loading) { binding.playerState.text = "Loading stream..." binding.playerProgress.isIndeterminate = true } else { binding.playerProgress.isIndeterminate = false } } viewModel.error.observe(viewLifecycleOwner) { error -> if (error != null) { binding.errorContainer.visibility = View.VISIBLE binding.errorMessage.text = error } else { binding.errorContainer.visibility = View.GONE } } } private fun updatePlayerUi(state: LofiViewModel.PlayerState) { binding.playerState.text = when (state) { LofiViewModel.PlayerState.IDLE -> "No stream playing" LofiViewModel.PlayerState.PLAYING -> "Playing" LofiViewModel.PlayerState.PAUSED -> "Paused" LofiViewModel.PlayerState.BUFFERING -> "Buffering..." LofiViewModel.PlayerState.ERROR -> "Error" LofiViewModel.PlayerState.ENDED -> "Stream ended" } binding.btnPlayPause.setImageResource( when (state) { LofiViewModel.PlayerState.PLAYING -> android.R.drawable.ic_media_pause else -> android.R.drawable.ic_btn_now_playing } ) binding.playerProgress.visibility = if (state == LofiViewModel.PlayerState.BUFFERING) { View.VISIBLE } else { View.INVISIBLE } } override fun onDestroyView() { super.onDestroyView() _binding = null } }