添加播放列表数据

This commit is contained in:
litingting 2024-09-25 19:00:03 +08:00
parent 96eecd07e7
commit 0f54dc33fb
16 changed files with 407 additions and 152 deletions

View File

@ -38,7 +38,7 @@ android {
dependencies {
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("com.google.android.material:material:1.12.0")
implementation("com.google.android.material:material:1.11.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.activity:activity:1.9.1")
testImplementation("junit:junit:4.13.2")

View File

@ -4,6 +4,9 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
@ -28,12 +31,11 @@
android:exported="false" />
<activity
android:name=".ui.activity.PlayActivity"
android:screenOrientation="portrait"
android:exported="false" />
<activity
android:name=".ui.activity.HomeActivity"
android:exported="false" />
<activity
android:name=".ui.activity.A_HomeActivity"
android:screenOrientation="portrait"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -41,6 +43,11 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.activity.A_HomeActivity"
android:exported="false" >
</activity>
<activity
android:name=".ui.activity.MainActivity"
android:exported="false" />

View File

@ -3,6 +3,10 @@ package com.hi.music.player;
import android.app.Application;
import android.content.Context;
import com.hi.music.player.api.MediaControllerStatusListener;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.media3.MyMediaControllerManager;
public class MusicApplication extends Application {
// private final static MusicApplication sInstance = new MusicApplication();
@ -19,5 +23,11 @@ public class MusicApplication extends Application {
public void onCreate() {
super.onCreate();
myApplication = this;
MyMediaControllerManager.getInstance().init(new MediaControllerStatusListener() {
@Override
public void onMediaControllerComplete(boolean isOk) {
CommonUtils.LogMsg("=-----mediaController+" + isOk);
}
});
}
}

View File

@ -3,7 +3,6 @@ package com.hi.music.player.api;
public interface MediaControllerListener {
void onMediaControllerComplete(boolean isOk);
void onPlayStatus(int playStatus);
}

View File

@ -0,0 +1,9 @@
package com.hi.music.player.api;
public interface MediaControllerStatusListener {
void onMediaControllerComplete(boolean isOk);
}

View File

@ -3,5 +3,8 @@ package com.hi.music.player.helper;
public class MyValue {
//-----------------------------PlayActivity
public static String KEY_PLAY_ACTIVITY_SINGER = "click_singer";
//播放错误
public static int PLAY_STATUS_CODE = -1;
//-----------------------------PlayActivity
}

View File

@ -29,6 +29,20 @@ public class ResponsePlayListInfo {
private String params;
private String musicVideoType;
//------------自定义属性由另外接口请求返回的数据流组装
private String audioUrlLow;
private String audioUrlMedium;
public long getDurationMs() {
return DurationMs;
}
@ -116,4 +130,21 @@ public class ResponsePlayListInfo {
public void setMusicVideoType(String musicVideoType) {
this.musicVideoType = musicVideoType;
}
public String getAudioUrlLow() {
return audioUrlLow;
}
public void setAudioUrlLow(String audioUrlLow) {
this.audioUrlLow = audioUrlLow;
}
public String getAudioUrlMedium() {
return audioUrlMedium;
}
public void setAudioUrlMedium(String audioUrlMedium) {
this.audioUrlMedium = audioUrlMedium;
}
}

View File

@ -15,7 +15,9 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.hi.music.player.MusicApplication;
import com.hi.music.player.api.MediaControllerListener;
import com.hi.music.player.api.MediaControllerStatusListener;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.helper.MyValue;
import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.network.RetrofitManager;
@ -29,6 +31,7 @@ public class MyMediaControllerManager {
private static volatile MyMediaControllerManager myMediaControllerManagerInstance;
private MediaController mediaController;
public static MyMediaControllerManager getInstance() {
if (myMediaControllerManagerInstance == null) {
synchronized (RetrofitManager.class) {
@ -40,7 +43,7 @@ public class MyMediaControllerManager {
return myMediaControllerManagerInstance;
}
public void init(MediaControllerListener mediaControllerListener){
public void init(MediaControllerStatusListener statusListener) {
SessionToken sessionToken =
new SessionToken(MusicApplication.myApplication, new ComponentName(MusicApplication.myApplication, PlaybackService.class));
ListenableFuture<MediaController> controllerFuture =
@ -52,35 +55,52 @@ public class MyMediaControllerManager {
// playerView.setPlayer(controllerFuture.get());
try {
mediaController = controllerFuture.get();
mediaController.addListener(new Player.Listener() {
@Override
public void onPlayerError(PlaybackException error) {
CommonUtils.LogMsg("=-----PlaybackException+"+error.getMessage());
}
@Override
public void onPlaybackStateChanged(int playbackState) {
CommonUtils.LogMsg("=-----playbackState+"+playbackState);
mediaControllerListener.onPlayStatus(playbackState);
}
@Override
public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
// 快进快退等操作
CommonUtils.LogMsg("=-----newPosition+"+newPosition.positionMs);
// mediaControllerListener.onPlayStatus(playbackState);
}
});
mediaControllerListener.onMediaControllerComplete(true);
CommonUtils.LogMsg("=-----mediaController+"+mediaController);
statusListener.onMediaControllerComplete(true);
CommonUtils.LogMsg("=-----mediaController+" + mediaController);
} catch (ExecutionException | InterruptedException e) {
CommonUtils.LogErrorMsg(e.getMessage());
mediaControllerListener.onMediaControllerComplete(false);
statusListener.onMediaControllerComplete(false);
}
}, MoreExecutors.directExecutor());
}
public void addListener(MediaControllerListener listener) {
mediaController.addListener(new Player.Listener() {
@Override
public void onPlayerError(PlaybackException error) {
CommonUtils.LogMsg("=-----PlaybackException+" + error.getMessage());
listener.onPlayStatus(MyValue.PLAY_STATUS_CODE);
}
@Override
public void onIsPlayingChanged(boolean isPlaying) {
CommonUtils.LogMsg("-----onIsPlayingChanged+" + isPlaying);
if (isPlaying) {
// 播放器开始播放
System.out.println("Playback started!");
} else {
// 播放器暂停或停止
System.out.println("Playback paused or stopped.");
}
}
@Override
public void onPlaybackStateChanged(int playbackState) {
listener.onPlayStatus(playbackState);
}
@Override
public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
// 快进快退等操作
CommonUtils.LogMsg("=-----快进、快退+" + newPosition.positionMs);
// mediaControllerListener.onPlayStatus(playbackState);
}
});
}
public MediaController getMediaController() {
@ -89,37 +109,105 @@ public class MyMediaControllerManager {
public long getContentPos() {
if (mediaController == null) return 0;
return mediaController.getContentPosition();
}
public long getBufferPos() {
if (mediaController == null) return 0;
return mediaController.getBufferedPosition();
}
/**
* 更新播放列表中的音频url
*
* @param playUrl
*/
@OptIn(markerClass = UnstableApi.class)
public void addMusicPlay(ResponsePlayListInfo playInfo, ResponsePlayUrl responsePlay){
List<MediaItem> mediaItems = new ArrayList<>();
MediaItem.Builder builder = new MediaItem.Builder();
if(responsePlay.getAudioUrlMedium()!= null){
builder.setUri(responsePlay.getAudioUrlMedium());
}else {
builder.setUri(responsePlay.getAudioUrlLow());
public void UpdateAudioUrl(ResponsePlayUrl playUrl) {
for (int i = 0; i < mediaController.getMediaItemCount(); i++) {
MediaItem mediaItemAt = mediaController.getMediaItemAt(i);
if (mediaItemAt.mediaId.equals(playUrl.getVideoId())) {
MediaItem.Builder builder = mediaItemAt.buildUpon();
if (playUrl.getAudioUrlMedium() != null) {
builder.setUri(playUrl.getAudioUrlMedium());
} else {
builder.setUri(playUrl.getAudioUrlLow());
}
mediaController.setMediaItem(builder.build(), i);
CharSequence title = mediaController.getMediaItemAt(i).mediaMetadata.title;
CommonUtils.LogMsg("-------------更新播放列表中的音频url= i=" + i + "---title=" + title);
break;
}
}
}
// @OptIn(markerClass = UnstableApi.class)
// public void addMusicPlay(ResponsePlayListInfo playInfo, ResponsePlayUrl responsePlay) {
// List<MediaItem> mediaItems = new ArrayList<>();
// MediaItem.Builder builder = new MediaItem.Builder();
// if (responsePlay.getAudioUrlMedium() != null) {
// builder.setUri(responsePlay.getAudioUrlMedium());
// } else {
// builder.setUri(responsePlay.getAudioUrlLow());
// }
//
// //唯一标识符
// builder.setMediaId(responsePlay.getVideoId());
//
// MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder();
//
// MediaMetadata_builder.setArtist(playInfo.getSingerName());
// MediaMetadata_builder.setDurationMs(playInfo.getDurationMs());
// MediaMetadata_builder.setAlbumArtist(playInfo.getCovert());
// MediaMetadata_builder.setTitle(playInfo.getSongTitle());
//// MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear()));
// builder.setMediaMetadata(MediaMetadata_builder.build());
//
// mediaItems.add(builder.build());
// mediaController.addMediaItems(mediaItems);
// mediaController.prepare();
//
// }
builder.setMediaId(responsePlay.getVideoId());
MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder();
MediaMetadata_builder.setArtist(playInfo.getSingerName());
// MediaMetadata_builder.setDurationMs( );
MediaMetadata_builder.setAlbumArtist(playInfo.getCovert());
MediaMetadata_builder.setTitle(playInfo.getSongTitle());
/**
* 添加播放列表不带音频url
*
* @param listInfo
*/
@OptIn(markerClass = UnstableApi.class)
public void addMusicPlayList(List<ResponsePlayListInfo> listInfo) {
List<MediaItem> mediaItems = new ArrayList<>();
for (int i = 0; i < listInfo.size(); i++) {
ResponsePlayListInfo playInfo = listInfo.get(i);
MediaItem.Builder builder = new MediaItem.Builder();
//唯一标识符
builder.setMediaId(playInfo.getVideoId());
MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder();
MediaMetadata_builder.setArtist(playInfo.getSingerName());
MediaMetadata_builder.setDurationMs(playInfo.getDurationMs());
MediaMetadata_builder.setAlbumArtist(playInfo.getCovert());
MediaMetadata_builder.setTitle(playInfo.getSongTitle());
// MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear()));
builder.setMediaMetadata(MediaMetadata_builder.build());
mediaItems.add(builder.build());
builder.setMediaMetadata(MediaMetadata_builder.build());
mediaItems.add(builder.build());
}
mediaController.addMediaItems(mediaItems);
}
public void play() {
mediaController.prepare();
if (!mediaController.isPlaying())
mediaController.play();
}
public void play(){
mediaController.play();
public void pause() {
if (mediaController.isPlaying())
mediaController.pause();
}
}

View File

@ -3,7 +3,9 @@ package com.hi.music.player.ui.activity;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Pair;
import android.view.View;
import android.widget.SeekBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -12,7 +14,6 @@ import androidx.core.content.ContextCompat;
import androidx.lifecycle.Observer;
import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.session.MediaController;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
@ -35,19 +36,31 @@ import com.hi.music.player.ui.activity.viewmodel.VMPlay;
import java.util.List;
public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
public class PlayActivity extends BaseActivity<ActivityPlayBinding> implements SeekBar.OnSeekBarChangeListener {
private ResponseSingle responseSingle;
private VMPlay vmPlay;
//接口返回的播放列表(没有音频数据)
private List<ResponsePlayListInfo> mPlayList;
//播放列对应的音频数据
private List<ResponsePlayUrl> mPlayUrls;
private ResponsePlayUrl mCurPlayInfo;
private ResponsePlayListInfo musicInfo;
private Handler mHandler;
private Runnable mRunnable;
private MyMediaControllerManager mediaControllerManager;
//请求播放列表是否成功
private boolean requestPlayList = false;
//请求第一首歌曲url是否成功
private boolean requestPlayUrl = false;
@Override
protected ActivityPlayBinding getViewBinding() {
return ActivityPlayBinding.inflate(getLayoutInflater());
@ -58,35 +71,38 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
Intent intent = getIntent();
responseSingle = (ResponseSingle) intent.getSerializableExtra(MyValue.KEY_PLAY_ACTIVITY_SINGER);
vmPlay = getActivityScopeViewModel(VMPlay.class);
vmPlay.getPlayUrl(responseSingle);
vmPlay.getPlayMusicList(responseSingle);
initPlayerView();
initMediaController();
initProgressHandler();
vmPlay.data.observe(this, new Observer<List<ResponsePlayListInfo>>() {
vmPlay.playList.observe(this, new Observer<List<ResponsePlayListInfo>>() {
@Override
public void onChanged(List<ResponsePlayListInfo> playList) {
if (playList.size() > 0) {
requestPlayList = true;
mPlayList = playList;
musicInfo = playList.get(0);
loadCovert(musicInfo.getCovert());
loadInfo(musicInfo);
startPlayMusic();
}
}
});
vmPlay.playUrlLiveData.observe(this, new Observer<ResponsePlayUrl>() {
vmPlay.playUrlLiveData.observe(this, new Observer<Pair<ResponsePlayUrl, Integer>>() {
@Override
public void onChanged(ResponsePlayUrl responsePlayUrl) {
mCurPlayInfo = responsePlayUrl;
public void onChanged(Pair<ResponsePlayUrl, Integer> responsePlayUrlIntegerPair) {
requestPlayUrl = true;
mCurPlayInfo = responsePlayUrlIntegerPair.first;
Integer second = responsePlayUrlIntegerPair.second;
CommonUtils.LogMsg("---------mCurPlayInfo=" + mCurPlayInfo.getAudioUrlLow());
startPlayMusic();
updateAudioUrl(responsePlayUrlIntegerPair.first);
if (second == 0) {
mediaControllerManager.play();
}
}
});
}
@ -99,35 +115,32 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
private void initMediaController() {
mediaControllerManager = MyMediaControllerManager.getInstance();
mediaControllerManager.init(new MediaControllerListener() {
@Override
public void onMediaControllerComplete(boolean isOk) {
MediaController mediaController1 = mediaControllerManager.getMediaController();
vb.playerView.setPlayer(mediaController1);
startPlayMusic();
}
mediaControllerManager.addListener(new MediaControllerListener() {
@Override
public void onPlayStatus(int playStatus) {
CommonUtils.LogMsg("-------------playStatus=" + playStatus);
switch (playStatus) {
case Player.STATE_IDLE:
break;
case Player.STATE_BUFFERING:
//快进没有缓冲的时候触发
vb.progressBarLoading.setVisibility(View.VISIBLE);
CommonUtils.LogMsg("-------------duration STATE_BUFFERING=");
break;
case Player.STATE_READY:
mHandler.post(mRunnable);
vb.progressBar.setVisibility(View.GONE);
vb.progressBarLoading.setVisibility(View.GONE);
break;
case Player.STATE_ENDED:
mHandler.removeCallbacks(mRunnable); // 停止更新
break;
case Player.STATE_BUFFERING:
updatePlayComplete();
break;
}
}
});
}
@ -135,53 +148,65 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
@Override
protected void onInitClick() {
vb.btnPlay.setOnClickListener(this::onClick);
vb.playProgress.setOnSeekBarChangeListener(this);
}
/**
* 更新播放进度Ui
* 更新播放进度Ui缓冲进度
*/
private void updatePlaybackProgress() {
// 获取当前播放位置
long contentPos = mediaControllerManager.getContentPos();
long currentPosition = mediaControllerManager.getMediaController().getCurrentPosition();
long duration = mediaControllerManager.getMediaController().getContentDuration();
long bufferPos = mediaControllerManager.getBufferPos();
long durationMs = musicInfo.getDurationMs();
String s = CommonUtils.convertMillisToTime(contentPos);
CommonUtils.LogMsg("---------播放进度-----contentPos=" + contentPos+"----currentPosition="+currentPosition+"------duration="+duration);
CommonUtils.LogMsg("---------播放进度-----contentPos=" + contentPos + "-----缓冲进度=" + bufferPos);
vb.tvCurrent.setText(s);
vb.seekbar.setValue(contentPos);
vb.playProgress.setProgress((int) contentPos);
vb.progressBarBuffer.setProgress((int) bufferPos);
}
/**
* 播放完成 更新播放进度Ui
*/
private void updatePlayComplete() {
vb.tvCurrent.setText(vb.tvDuration.getText().toString());
}
/**
* 初始化当前播放歌曲信息
*
* @param data
*/
private void loadInfo(ResponsePlayListInfo data) {
vb.tvSongName.setText(data.getSongTitle());
vb.tvSingerName.setText(data.getSingerName());
vb.tvDuration.setText(data.getDuration());
vb.seekbar.setValueTo(data.getDurationMs());
long durationMs = data.getDurationMs();
vb.playProgress.setMax((int) durationMs);
vb.progressBarBuffer.setMax((int) data.getDurationMs());
CommonUtils.LogMsg("--------------data.getDurationMs() 22222222222=" + durationMs);
}
private void startPlayMusic() {
initProgressHandler();
CommonUtils.LogMsg("00000");
MediaController mediaController = mediaControllerManager.getMediaController();
if (mCurPlayInfo != null && mediaController != null && mPlayList != null) {
mediaControllerManager.addMusicPlay(mPlayList.get(0), mCurPlayInfo);
mediaControllerManager.play();
CommonUtils.LogMsg("111");
}
/**
* 更新音频url到播放列表
*/
private void updateAudioUrl(ResponsePlayUrl playUrl) {
mediaControllerManager.UpdateAudioUrl(playUrl);
}
private void loadCovert(String url) {
Glide.with(MusicApplication.myApplication)
.asDrawable()
@ -213,8 +238,7 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
@Override
public void run() {
updatePlaybackProgress();
// 继续定时更新
mHandler.postDelayed(this, 1000); // 每秒更新一次
mHandler.postDelayed(this, 1000);
}
};
}
@ -233,6 +257,11 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
public void onClick(View v) {
if (v.equals(vb.btnPlay)) {
vb.btnPlay.setSelected(!vb.btnPlay.isSelected());
if (vb.btnPlay.isSelected()) {
mediaControllerManager.play();
} else {
mediaControllerManager.pause();
}
}
}
@ -243,4 +272,23 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
if (mHandler != null && mRunnable != null)
mHandler.removeCallbacks(mRunnable);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
CommonUtils.LogMsg("---------onProgressChanged----progress=" + progress);
mediaControllerManager.getMediaController().seekTo(progress);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}

View File

@ -1,5 +1,7 @@
package com.hi.music.player.ui.activity.viewmodel;
import android.util.Pair;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
@ -9,6 +11,7 @@ import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.javabean.response.child.ResponseSingle;
import com.hi.music.player.media3.MyMediaControllerManager;
import com.hi.music.player.network.JsonHelper;
import com.hi.music.player.network.RetrofitManager;
@ -21,12 +24,12 @@ import okhttp3.ResponseBody;
public class VMPlay extends ViewModel {
private MutableLiveData<List<ResponsePlayListInfo>> _data = new MutableLiveData<List<ResponsePlayListInfo>>();
public LiveData<List<ResponsePlayListInfo>> data = _data;
private MutableLiveData<List<ResponsePlayListInfo>> _playList = new MutableLiveData<List<ResponsePlayListInfo>>();
public LiveData<List<ResponsePlayListInfo>> playList = _playList;
private MutableLiveData<ResponsePlayUrl> _playUrlMutableLiveData = new MutableLiveData<ResponsePlayUrl>();
public LiveData<ResponsePlayUrl> playUrlLiveData = _playUrlMutableLiveData;
private MutableLiveData<Pair<ResponsePlayUrl, Integer>> _playUrlMutableLiveData = new MutableLiveData<Pair<ResponsePlayUrl, Integer>>();
public LiveData<Pair<ResponsePlayUrl, Integer>> playUrlLiveData = _playUrlMutableLiveData;
private String continuation, clickTrackingParams, visitorData;
@ -40,7 +43,7 @@ public class VMPlay extends ViewModel {
@Override
public void onFail(String errorMsg) {
_data.setValue(null);
_playList.setValue(null);
}
@Override
@ -48,16 +51,18 @@ public class VMPlay extends ViewModel {
JSONObject jsonObject = CommonUtils.toJsonObject(data);
if (jsonObject != null) {
List<ResponsePlayListInfo> responsePlayListInfos = JsonHelper.ResolvePlayListJson(jsonObject);
_data.setValue(responsePlayListInfos);
MyMediaControllerManager.getInstance().addMusicPlayList(responsePlayListInfos);
_playList.setValue(responsePlayListInfos);
getPlayUrl(responseSingle,0);
} else {
_data.setValue(null);
_playList.setValue(null);
}
}
});
}
public void getPlayUrl(ResponseSingle responseSingle) {
public void getPlayUrl(ResponseSingle responseSingle, int playListIndex) {
String videoId = responseSingle.getVideoId();
RetrofitManager.getInstance().getPlayUrl(videoId, new RequestListener<ResponseBody>() {
@ -71,7 +76,7 @@ public class VMPlay extends ViewModel {
JSONObject jsonObject = CommonUtils.toJsonObject(data);
if (jsonObject != null) {
ResponsePlayUrl responsePlayUrl = JsonHelper.ResolvePlayUrlJson(jsonObject);
_playUrlMutableLiveData.setValue(responsePlayUrl);
_playUrlMutableLiveData.setValue(new Pair<>(responsePlayUrl, playListIndex));
} else {
_playUrlMutableLiveData.setValue(null);
}

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="10dp" />
<solid android:color="@color/color_transparent" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="10dp" />
<solid android:color="@color/progress_buffer_color"/>
</shape>
</clip>
</item>
</layer-list>

View File

@ -4,7 +4,7 @@
<solid android:color="@color/white" />
<size
android:width="13dp"
android:height="13dp" />
android:width="9dp"
android:height="9dp" />
</shape>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false" android:drawable="@mipmap/icon_pause"/>
<item android:state_selected="true" android:drawable="@mipmap/icon_play"/>
<item android:state_selected="false" android:drawable="@mipmap/icon_play"/>
<item android:state_selected="true" android:drawable="@mipmap/icon_pause"/>
</selector>

View File

@ -27,33 +27,32 @@
android:layout_marginTop="30dp"
android:layout_marginEnd="40dp"
android:scaleType="fitXY"
android:src="@mipmap/ic_launcher"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back" />
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:show_buffering="when_playing"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back"
app:show_shuffle_button="true"/>
app:show_buffering="when_playing"
app:show_shuffle_button="true" />
<ProgressBar
android:id="@+id/progressBarLoading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateTint="@color/white"
app:layout_constraintBottom_toBottomOf="@id/im_covert"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
android:indeterminateTint="@color/white"
android:id="@+id/progressBar"
android:visibility="invisible"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toTopOf="@id/im_covert" />
@ -79,57 +78,81 @@
app:layout_constraintLeft_toLeftOf="@id/tv_song_name"
app:layout_constraintTop_toBottomOf="@id/tv_song_name" />
<com.google.android.material.slider.Slider
android:id="@+id/seekbar"
<!-- <com.google.android.material.slider.Slider-->
<!-- android:id="@+id/play_progress"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:value="0"-->
<!-- android:valueFrom="0"-->
<!-- android:valueTo="100"-->
<!-- app:labelBehavior="gone"-->
<!-- app:layout_constraintLeft_toLeftOf="parent"-->
<!-- app:layout_constraintRight_toRightOf="parent"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tv_singer_name"-->
<!-- app:thumbColor="@color/white"-->
<!-- app:thumbElevation="0dp"-->
<!-- android:paddingStart="0dp"-->
<!-- android:paddingEnd="0dp"-->
<!-- app:thumbRadius="4dp"-->
<!-- app:trackColorActive="@color/white"-->
<!-- app:trackColorInactive="@color/seek_bg_color"-->
<!-- app:trackHeight="3dp" />-->
<SeekBar
android:id="@+id/play_progress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="35dp"
android:layout_marginTop="25dp"
android:layout_marginEnd="35dp"
android:maxHeight="3dp"
android:paddingLeft="0dp"
android:paddingEnd="5dp"
android:paddingRight="0dp"
android:paddingStart="5dp"
android:progress="30"
android:progressDrawable="@drawable/seekbar_progress_drawable"
android:thumb="@drawable/seekbar_thumb"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_singer_name" />
<ProgressBar
android:id="@+id/progressBar_buffer"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:valueFrom="0"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toBottomOf="@id/tv_singer_name"
app:labelBehavior="gone"
app:thumbColor="@color/white"
app:thumbRadius="6dp"
app:trackColorActive="@color/white"
app:trackColorInactive="#00000000"
app:trackHeight="3dp" />
<SeekBar
android:id="@+id/seekbar1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="25dp"
android:maxHeight="3dp"
android:paddingStart="0dp"
android:paddingLeft="0dp"
android:paddingEnd="0dp"
android:paddingRight="0dp"
android:progress="10"
android:visibility="gone"
android:progressDrawable="@drawable/seekbar_progress_drawable"
android:thumb="@drawable/seekbar_thumb"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toBottomOf="@id/tv_singer_name" />
android:layout_height="3dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:progress="100"
android:progressDrawable="@drawable/horizontal_progressbar"
app:layout_constraintBottom_toBottomOf="@id/play_progress"
app:layout_constraintLeft_toLeftOf="@id/play_progress"
app:layout_constraintRight_toRightOf="@id/play_progress"
app:layout_constraintTop_toTopOf="@id/play_progress" />
<TextView
android:id="@+id/tv_current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="1:23"
android:paddingStart="5dp"
android:text="0:00"
android:textColor="@color/white_60_color"
app:layout_constraintStart_toStartOf="@id/seekbar"
app:layout_constraintTop_toBottomOf="@id/seekbar" />
app:layout_constraintStart_toStartOf="@id/play_progress"
app:layout_constraintTop_toBottomOf="@id/play_progress" />
<TextView
android:id="@+id/tv_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="1:23"
android:paddingEnd="5dp"
android:text="0:00"
android:textColor="@color/white_60_color"
app:layout_constraintEnd_toEndOf="@id/seekbar"
app:layout_constraintTop_toBottomOf="@id/seekbar" />
app:layout_constraintEnd_toEndOf="@id/play_progress"
app:layout_constraintTop_toBottomOf="@id/play_progress" />
<ImageView
android:id="@+id/btn_play"
@ -172,6 +195,4 @@
app:layout_constraintLeft_toLeftOf="@id/im_covert" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -8,4 +8,7 @@
<color name="seek_bg_color">#4DFFFFFF</color>
<color name="white_60_color">#99FFFFFF</color>
<color name="progress_buffer_color">#59FFFFFF</color>
<color name="test">#2D9C31</color>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- <style name="Slider.NoMargin" parent="Widget.Material3.Slider">-->
<!-- <item name="trackMarginStart">0dp</item>-->
<!-- <item name="trackMarginEnd">0dp</item>-->
<!-- </style>-->
</resources>