Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package ir.hanzodev1375.ghostide.fragments;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import java.io.File;
import ir.hanzodev1375.ghostide.R;
import ir.hanzodev1375.ghostide.utils.MusicPlayerManager;

public class MusicPlayerBottomSheetFragment extends BottomSheetDialogFragment implements MusicPlayerManager.PlaybackListener {
private TextView songTitle;
private SeekBar seekBar;
private ImageButton btnPlayPause;
private MusicPlayerManager playerManager;
private Handler handler = new Handler(Looper.getMainLooper());
private Runnable updateSeekBar;

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_music_player, container, false);
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
songTitle = view.findViewById(R.id.songTitle);
seekBar = view.findViewById(R.id.seekBar);
btnPlayPause = view.findViewById(R.id.btnPlayPause);
ImageButton btnPrev = view.findViewById(R.id.btnPrevious);
ImageButton btnNext = view.findViewById(R.id.btnNext);

playerManager = MusicPlayerManager.getInstance(requireContext());
playerManager.addPlaybackListener(this);

String currentPath = playerManager.getCurrentSongPath();
if (currentPath != null) {
songTitle.setText(new File(currentPath).getName());
updatePlayPauseButton();
if (playerManager.isPlaying()) {
startUpdatingSeekBar();
}
}

btnPlayPause.setOnClickListener(v -> {
if (playerManager.isPlaying()) {
playerManager.pause();
} else {
if (playerManager.getCurrentSongPath() != null) {
playerManager.resume();
} else {
dismiss();
}
}
updatePlayPauseButton();
});

btnPrev.setOnClickListener(v -> {});
btnNext.setOnClickListener(v -> {});

seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
playerManager.seekTo(progress);
}
}
@Override public void onStartTrackingTouch(SeekBar seekBar) {}
@Override public void onStopTrackingTouch(SeekBar seekBar) {}
});
}

@Override
public void onPlaybackStarted(String path) {
songTitle.setText(new File(path).getName());
updatePlayPauseButton();
seekBar.setMax(playerManager.getDuration());
startUpdatingSeekBar();
}

@Override
public void onPlaybackPaused() {
updatePlayPauseButton();
stopUpdatingSeekBar();
}

@Override
public void onPlaybackResumed() {
updatePlayPauseButton();
startUpdatingSeekBar();
}

@Override
public void onPlaybackStopped() {
updatePlayPauseButton();
stopUpdatingSeekBar();
dismiss();
}

@Override
public void onPlaybackCompleted() {
updatePlayPauseButton();
stopUpdatingSeekBar();
dismiss();
}

@Override
public void onPositionChanged(int position) {
seekBar.setProgress(position);
}

private void updatePlayPauseButton() {
if (playerManager.isPlaying()) {
btnPlayPause.setImageResource(android.R.drawable.ic_media_pause);
} else {
btnPlayPause.setImageResource(android.R.drawable.ic_media_play);
}
}

private void startUpdatingSeekBar() {
if (updateSeekBar != null) stopUpdatingSeekBar();
updateSeekBar = new Runnable() {
@Override
public void run() {
if (playerManager.isPlaying()) {
seekBar.setProgress(playerManager.getCurrentPosition());
handler.postDelayed(this, 500);
}
}
};
handler.post(updateSeekBar);
}

private void stopUpdatingSeekBar() {
if (updateSeekBar != null) {
handler.removeCallbacks(updateSeekBar);
updateSeekBar = null;
}
}

@Override
public void onDestroyView() {
super.onDestroyView();
playerManager.removePlaybackListener(this);
stopUpdatingSeekBar();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package ir.hanzodev1375.ghostide.utils;

import android.content.Context;
import android.media.MediaPlayer;
import android.os.Handler;
import android.os.Looper;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class MusicPlayerManager {
private static MusicPlayerManager instance;
private Context context;
private MediaPlayer mediaPlayer;
private String currentSongPath;
private boolean isPlaying;
private int currentPosition;
private List<PlaybackListener> listeners = new ArrayList<>();

private MusicPlayerManager(Context context) {
this.context = context.getApplicationContext();
}

public static synchronized MusicPlayerManager getInstance(Context context) {
if (instance == null) {
instance = new MusicPlayerManager(context);
}
return instance;
}

public void play(String path) {
try {
if (mediaPlayer != null) {
mediaPlayer.release();
}
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(path);
mediaPlayer.prepare();
mediaPlayer.start();
currentSongPath = path;
isPlaying = true;
notifyPlaybackStarted();
setupCompletionListener();
setupPositionUpdater();
} catch (Exception e) {
e.printStackTrace();
}
}

public void pause() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
isPlaying = false;
notifyPlaybackPaused();
}
}

public void resume() {
if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
mediaPlayer.start();
isPlaying = true;
notifyPlaybackResumed();
}
}

public void stop() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
isPlaying = false;
currentSongPath = null;
notifyPlaybackStopped();
}
}

public boolean isPlaying() {
return isPlaying;
}

public String getCurrentSongPath() {
return currentSongPath;
}

public int getDuration() {
if (mediaPlayer != null) {
return mediaPlayer.getDuration();
}
return 0;
}

public int getCurrentPosition() {
if (mediaPlayer != null && isPlaying) {
currentPosition = mediaPlayer.getCurrentPosition();
}
return currentPosition;
}

public void seekTo(int position) {
if (mediaPlayer != null) {
mediaPlayer.seekTo(position);
currentPosition = position;
}
}

private void setupCompletionListener() {
if (mediaPlayer != null) {
mediaPlayer.setOnCompletionListener(mp -> {
isPlaying = false;
currentSongPath = null;
notifyPlaybackCompleted();
});
}
}

private void setupPositionUpdater() {
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (mediaPlayer != null && isPlaying) {
currentPosition = mediaPlayer.getCurrentPosition();
notifyPositionChanged(currentPosition);
handler.postDelayed(this, 500);
}
}
}, 500);
}

public void addPlaybackListener(PlaybackListener listener) {
if (!listeners.contains(listener)) {
listeners.add(listener);
}
}

public void removePlaybackListener(PlaybackListener listener) {
listeners.remove(listener);
}

private void notifyPlaybackStarted() {
for (PlaybackListener l : listeners) {
l.onPlaybackStarted(currentSongPath);
}
}

private void notifyPlaybackPaused() {
for (PlaybackListener l : listeners) {
l.onPlaybackPaused();
}
}

private void notifyPlaybackResumed() {
for (PlaybackListener l : listeners) {
l.onPlaybackResumed();
}
}

private void notifyPlaybackStopped() {
for (PlaybackListener l : listeners) {
l.onPlaybackStopped();
}
}

private void notifyPlaybackCompleted() {
for (PlaybackListener l : listeners) {
l.onPlaybackCompleted();
}
}

private void notifyPositionChanged(int position) {
for (PlaybackListener l : listeners) {
l.onPositionChanged(position);
}
}

public interface PlaybackListener {
void onPlaybackStarted(String path);
void onPlaybackPaused();
void onPlaybackResumed();
void onPlaybackStopped();
void onPlaybackCompleted();
void onPositionChanged(int position);
}
}
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/bottom_sheet_background.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/white" />
<corners android:topLeftRadius="24dp" android:topRightRadius="24dp" />
</shape>
Binary file added app/src/main/res/drawable/ic_music.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading