A面前台播放优化

This commit is contained in:
lihongwei 2024-09-30 10:49:55 +08:00
parent 129680cb45
commit 90564a274c
17 changed files with 450 additions and 329 deletions

View File

@ -7,6 +7,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.DiffUtil;
@ -43,6 +44,9 @@ public class A_InstrumentAdapter extends RecyclerView.Adapter<A_InstrumentAdapte
Log.d("------","--------"+audioItem.getImage()); Log.d("------","--------"+audioItem.getImage());
holder.textView1.setText(audioItem.getName());
holder.textView2.setText(audioItem.getName());
Glide.with(context) Glide.with(context)
.load("file:///android_asset/" + audioItem.getImage()) // 正确的路径 .load("file:///android_asset/" + audioItem.getImage()) // 正确的路径
.into(holder.imageView); .into(holder.imageView);
@ -75,11 +79,15 @@ public class A_InstrumentAdapter extends RecyclerView.Adapter<A_InstrumentAdapte
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView; ImageView imageView;
TextView textView1;
TextView textView2;
public ViewHolder(@NonNull View itemView) { public ViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
imageView = itemView.findViewById(R.id.background_image); imageView = itemView.findViewById(R.id.background_image);
textView1 = itemView.findViewById(R.id.title);
textView2 = itemView.findViewById(R.id.time);
} }
} }
} }

View File

@ -6,6 +6,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.DiffUtil;
@ -40,6 +41,8 @@ public class A_NatureAdapter extends RecyclerView.Adapter<A_NatureAdapter.ViewHo
AudioItem audioItem = audioItems.get(position); AudioItem audioItem = audioItems.get(position);
holder.textView1.setText(audioItem.getName());
holder.textView2.setText(audioItem.getName());
Glide.with(context) Glide.with(context)
.load("file:///android_asset/" + audioItem.getImage()) .load("file:///android_asset/" + audioItem.getImage())
@ -73,12 +76,16 @@ public class A_NatureAdapter extends RecyclerView.Adapter<A_NatureAdapter.ViewHo
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView; ImageView imageView;
TextView textView1;
TextView textView2;
public ViewHolder(@NonNull View itemView) { public ViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
imageView = itemView.findViewById(R.id.cover); imageView = itemView.findViewById(R.id.cover);
textView1 = itemView.findViewById(R.id.title);
textView2 = itemView.findViewById(R.id.time);
} }
} }

View File

@ -7,6 +7,7 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.DiffUtil;
@ -43,6 +44,8 @@ public class A_WhiteAdapter extends RecyclerView.Adapter<A_WhiteAdapter.ViewHold
Log.d("------","--------"+audioItem.getImage()); Log.d("------","--------"+audioItem.getImage());
holder.textView1.setText(audioItem.getName());
holder.textView2.setText(audioItem.getName());
// 加载图片确保不使用 file:// 前缀并将路径传递给 Glide // 加载图片确保不使用 file:// 前缀并将路径传递给 Glide
Glide.with(context) Glide.with(context)
@ -77,12 +80,16 @@ public class A_WhiteAdapter extends RecyclerView.Adapter<A_WhiteAdapter.ViewHold
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
private ImageView imageView; ImageView imageView;
TextView textView1;
TextView textView2;
public ViewHolder(@NonNull View itemView) { public ViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
imageView = itemView.findViewById(R.id.image); imageView = itemView.findViewById(R.id.image);
textView1 = itemView.findViewById(R.id.title);
textView2 = itemView.findViewById(R.id.time);
} }

View File

@ -5,7 +5,6 @@ import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.ContentResolver;
import android.content.Intent; import android.content.Intent;
import android.content.res.AssetFileDescriptor; import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer; import android.media.MediaPlayer;
@ -13,154 +12,248 @@ import android.net.Uri;
import android.os.Binder; import android.os.Binder;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
import android.util.Log;
import com.hi.music.player.R; import com.hi.music.player.R;
import com.hi.music.player.ui.activity.A_PlayActivity; import com.hi.music.player.ui.activity.A_PlayActivity;
import java.io.File;
import java.io.IOException; import java.io.IOException;
public class MusicPlayerForegroundService extends Service { public class MusicPlayerForegroundService extends Service {
// 通知渠道ID用于创建通知渠道
public static final String CHANNEL_ID = "MusicPlayerChannel"; public static final String CHANNEL_ID = "MusicPlayerChannel";
private MediaPlayer mediaPlayer; private MediaPlayer mediaPlayer; // MediaPlayer实例用于播放音频
private final IBinder binder = new MusicBinder(); private final IBinder binder = new MusicBinder(); // 用于绑定服务的Binder
private MutableLiveData<Boolean> isPlaying = new MutableLiveData<>(false); private final MutableLiveData<Boolean> isPlaying = new MutableLiveData<>(false); // 用于跟踪播放状态的LiveData
private final MutableLiveData<String> fileName = new MutableLiveData<>(); // 保存当前播放的文件名
private String currentAudioPath = null; // 用于保存当前正在播放的音频路径
// 自定义Binder类允许客户端绑定到服务
public class MusicBinder extends Binder { public class MusicBinder extends Binder {
public MusicPlayerForegroundService getService() { public MusicPlayerForegroundService getService() {
return MusicPlayerForegroundService.this; return MusicPlayerForegroundService.this; // 返回当前服务实例
} }
} }
@Nullable @Nullable
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return binder; return binder; // 返回用于绑定服务的Binder
} }
// 当服务启动时调用该方法
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
String audioPath = intent.getStringExtra("Path"); // 从Intent中获取传入的音频路径
if (audioPath != null) { String newAudioPath = intent.getStringExtra("Path");
initializePlayer(audioPath);
if (newAudioPath != null) {
// 如果传入的音频路径与当前播放路径不同则重新初始化播放器
if (currentAudioPath == null || !newAudioPath.equals(currentAudioPath)) {
Log.d("MusicPlayerService", "检测到新的音频路径,初始化播放器");
currentAudioPath = newAudioPath; // 更新当前播放路径
stopAndResetMediaPlayer(); // 停止并重置当前的播放器状态
initializePlayer(newAudioPath); // 初始化播放器并开始播放新的音频
} else {
Log.d("MusicPlayerService", "音频路径相同,无需重新初始化播放器");
}
} else {
stopSelf(); // 如果路径为空停止服务
} }
startForeground(1, createNotification("Playing Audio", "Your audio is playing")); // 启动前台服务并显示通知
startForeground(1, createNotification());
return START_NOT_STICKY; return START_NOT_STICKY; // 返回START_NOT_STICKY表示服务不会在被系统杀死后自动重启
} }
private Notification createNotification(String title, String content) { // 创建通知用于前台服务显示
createNotificationChannel(); private Notification createNotification() {
Intent notificationIntent = new Intent(this, A_PlayActivity.class); createNotificationChannel(); // 创建通知渠道适用于Android O及以上版本
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
flags |= PendingIntent.FLAG_IMMUTABLE;
}
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, flags);
// 创建点击通知时打开的Intent
Intent notificationIntent = new Intent(this, A_PlayActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0); // 适配Android 12
// 构建通知设置标题内容和小图标
return new NotificationCompat.Builder(this, CHANNEL_ID) return new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(title) .setContentTitle("Playing Audio") // 通知标题
.setContentText(content) .setContentText("Your audio is playing") // 通知内容
.setSmallIcon(R.drawable.home_select) .setSmallIcon(R.drawable.home_select) // 通知的小图标
.setContentIntent(pendingIntent) .setContentIntent(pendingIntent) // 点击通知后的Intent
.setPriority(NotificationCompat.PRIORITY_LOW) .setPriority(NotificationCompat.PRIORITY_LOW) // 低优先级避免干扰用户
.build(); .build();
} }
// 创建通知渠道适用于Android O及以上版本
private void createNotificationChannel() { private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel( NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID, "Music Player Channel", NotificationManager.IMPORTANCE_LOW); CHANNEL_ID, "Music Player Channel", NotificationManager.IMPORTANCE_LOW);
NotificationManager manager = getSystemService(NotificationManager.class); NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel); if (manager != null) {
manager.createNotificationChannel(serviceChannel); // 创建通知渠道
}
} }
} }
// 停止并重置播放器确保在播放新的音频时播放器状态正确
private void stopAndResetMediaPlayer() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.stop(); // 停止正在播放的音频
}
mediaPlayer.reset(); // 重置播放器状态使其可以播放新的音频
}
}
// 初始化媒体播放器并设置数据源
private void initializePlayer(String path) { private void initializePlayer(String path) {
try { try {
Log.d("MediaPlayerError","path: "+path); Log.d("MusicPlayerService", "正在初始化播放器,音频路径: " + path);
if (mediaPlayer == null) { if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer(); mediaPlayer = new MediaPlayer(); // 如果MediaPlayer为空则创建一个新的实例
} else {
mediaPlayer.reset();
} }
if (path.startsWith("content://")) { // 设置当前播放的文件名
Uri contentUri = Uri.parse(path); fileName.setValue(getFileNameFromPath(path));
ContentResolver contentResolver = getContentResolver();
AssetFileDescriptor afd = contentResolver.openAssetFileDescriptor(contentUri, "r");
if (afd != null) {
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
}
} else {
AssetFileDescriptor afd = getAssets().openFd(path);
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
}
mediaPlayer.prepare(); // 根据传入的音频路径类型设置数据源
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start()); setDataSource(path);
isPlaying.postValue(true);
} catch (IOException e) { mediaPlayer.prepareAsync(); // 异步准备播放器
Log.e("MediaPlayerError", "Could not open file: " + path, e); mediaPlayer.setOnPreparedListener(mp -> {
mediaPlayer.start(); // 播放器准备好后开始播放
isPlaying.postValue(true); // 更新播放状态为播放中
});
// 设置播放完成后的监听器
mediaPlayer.setOnCompletionListener(mp -> {
isPlaying.postValue(false); // 更新播放状态为未播放
stopSelf(); // 播放完成后停止服务
});
// 设置播放错误的监听器
mediaPlayer.setOnErrorListener((mp, what, extra) -> {
Log.e("MusicPlayerService", "播放时发生错误: " + what + ", 额外信息: " + extra);
isPlaying.postValue(false); // 更新播放状态为未播放
stopSelf(); // 播放出错后停止服务
return true; // 返回true表示错误已经被处理
});
} catch (IOException | IllegalArgumentException | IllegalStateException e) {
Log.e("MusicPlayerService", "初始化播放器失败,路径: " + path, e);
isPlaying.postValue(false); // 如果初始化失败更新状态为未播放
stopSelf(); // 初始化失败后停止服务
} }
} }
// 设置数据源根据音频路径的类型来加载音频
private void setDataSource(String path) throws IOException {
if (path.startsWith("content://")) {
setDataSourceFromContentUri(path); // 如果是内容URI使用内容URI加载
} else {
setDataSourceFromFileOrAsset(path); // 否则尝试从文件或资产目录中加载
}
}
// 使用内容URI加载音频数据源
private void setDataSourceFromContentUri(String path) throws IOException {
Uri contentUri = Uri.parse(path); // 将字符串路径解析为URI
try (AssetFileDescriptor afd = getContentResolver().openAssetFileDescriptor(contentUri, "r")) {
if (afd != null) {
// 使用文件描述符和偏移量设置MediaPlayer的数据源
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
} else {
throw new IOException("无法打开内容URI: " + path);
}
}
}
// 尝试从文件或assets目录加载音频数据源
private void setDataSourceFromFileOrAsset(String path) throws IOException {
try {
// 尝试从assets目录加载音频
AssetFileDescriptor afd = getAssets().openFd(path);
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
} catch (IOException e) {
// 如果assets加载失败则尝试从文件系统加载音频
File file = new File(path);
if (file.exists()) {
mediaPlayer.setDataSource(file.getAbsolutePath()); // 从文件路径加载
} else {
throw new IOException("文件未找到: " + path);
}
}
}
// 根据路径获取文件名
private String getFileNameFromPath(String path) {
try {
return new File(path).getName(); // 从路径中提取文件名
} catch (Exception e) {
Log.e("MusicPlayerService", "获取文件名失败", e);
return "未知文件"; // 如果失败返回默认文件名
}
}
// 暂停音频播放
public void pauseAudio() { public void pauseAudio() {
if (mediaPlayer != null && mediaPlayer.isPlaying()) { if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause(); mediaPlayer.pause(); // 如果当前正在播放则暂停音频
isPlaying.postValue(false); isPlaying.postValue(false); // 更新播放状态为暂停
} }
} }
// 恢复音频播放
public void resumeAudio() { public void resumeAudio() {
if (mediaPlayer != null && !mediaPlayer.isPlaying()) { if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
mediaPlayer.start(); mediaPlayer.start(); // 如果当前未播放则恢复音频播放
isPlaying.postValue(true); isPlaying.postValue(true); // 更新播放状态为播放中
} }
} }
// 获取当前播放状态
public MutableLiveData<Boolean> getIsPlaying() { public MutableLiveData<Boolean> getIsPlaying() {
return isPlaying; return isPlaying;
} }
// 添加获取当前播放位置的方法 // 获取当前播放的文件名
public MutableLiveData<String> getFileName() {
return fileName;
}
// 获取当前播放位置毫秒
public int getCurrentPosition() { public int getCurrentPosition() {
if (mediaPlayer != null) { return mediaPlayer != null ? mediaPlayer.getCurrentPosition() : 0;
return mediaPlayer.getCurrentPosition();
}
return 0; // 如果 mediaPlayer null返回 0
} }
// 添加获取总时长的方法 // 获取音频总时长毫秒
public int getDuration() { public int getDuration() {
if (mediaPlayer != null) { return mediaPlayer != null ? mediaPlayer.getDuration() : 0;
return mediaPlayer.getDuration();
}
return 0; // 如果 mediaPlayer null返回 0
} }
// 跳转到指定播放位置
public void seekTo(int position) { public void seekTo(int position) {
if (mediaPlayer != null) { if (mediaPlayer != null) {
mediaPlayer.seekTo(position); mediaPlayer.seekTo(position); // 将播放器跳转到指定位置
} }
} }
// 当服务销毁时释放MediaPlayer资源
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (mediaPlayer != null) { if (mediaPlayer != null) {
mediaPlayer.release(); mediaPlayer.release(); // 释放MediaPlayer资源
mediaPlayer = null; mediaPlayer = null; // 将播放器设置为null防止再次使用
} }
} }
} }

View File

@ -1,35 +1,48 @@
package com.hi.music.player.ui.activity; package com.hi.music.player.ui.activity;
import android.util.Log; import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator; import com.google.android.material.tabs.TabLayoutMediator;
import com.hi.music.player.R; import com.hi.music.player.R;
import com.hi.music.player.adapter.A_HomeViewPagerAdapter; import com.hi.music.player.adapter.A_HomeViewPagerAdapter;
import com.hi.music.player.databinding.ActivityAhomeBinding; import com.hi.music.player.databinding.ActivityAhomeBinding;
import com.hi.music.player.databinding.HomeTabCustomBinding; import com.hi.music.player.databinding.HomeTabCustomBinding;
import com.hi.music.player.helper.CircularProgressBar; import com.hi.music.player.service.MusicPlayerForegroundService;
import com.hi.music.player.ui.activity.viewmodel.A_VMPlay;
import java.util.Objects; import java.util.Locale;
public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> { public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
private final int[] defaultIcons = { private final int[] defaultIcons = { R.drawable.home_unselect, R.drawable.import_unselect };
R.drawable.home_unselect, private final int[] selectedIcons = { R.drawable.home_select, R.drawable.import_select };
R.drawable.import_unselect,
};
private final int[] selectedIcons = { private MusicPlayerForegroundService musicService;
R.drawable.home_select, private boolean isBound = false;
R.drawable.import_select, private Handler progressHandler;
};
private A_VMPlay viewModel; private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
musicService = ((MusicPlayerForegroundService.MusicBinder) service).getService();
isBound = true;
setupObservers();
startUpdatingProgress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
@Override @Override
protected ActivityAhomeBinding getViewBinding() { protected ActivityAhomeBinding getViewBinding() {
@ -38,9 +51,10 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
@Override @Override
protected void onCreateInit() { protected void onCreateInit() {
viewModel = new ViewModelProvider(this).get(A_VMPlay.class); Intent serviceIntent = new Intent(this, MusicPlayerForegroundService.class);
startService(serviceIntent);
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
initData(); initData();
setupObservers();
} }
@Override @Override
@ -50,7 +64,7 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
@Override @Override
public boolean isFullScreen() { public boolean isFullScreen() {
return true; return false;
} }
@Override @Override
@ -58,11 +72,20 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
return false; return false;
} }
public void initData() { private void initData() {
setupViewPager();
setupTabLayout();
setupProgressBar();
setupPauseButton();
}
private void setupViewPager() {
A_HomeViewPagerAdapter adapter = new A_HomeViewPagerAdapter(this); A_HomeViewPagerAdapter adapter = new A_HomeViewPagerAdapter(this);
vb.homeViewpager.setAdapter(adapter); vb.homeViewpager.setAdapter(adapter);
vb.homeViewpager.setUserInputEnabled(false); vb.homeViewpager.setUserInputEnabled(false);
}
private void setupTabLayout() {
new TabLayoutMediator(vb.homeTabLayout, vb.homeViewpager, (tab, position) -> { new TabLayoutMediator(vb.homeTabLayout, vb.homeViewpager, (tab, position) -> {
HomeTabCustomBinding tabBinding = HomeTabCustomBinding.inflate(LayoutInflater.from(this)); HomeTabCustomBinding tabBinding = HomeTabCustomBinding.inflate(LayoutInflater.from(this));
tab.setCustomView(tabBinding.getRoot()); tab.setCustomView(tabBinding.getRoot());
@ -81,60 +104,112 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
} }
@Override @Override
public void onTabReselected(TabLayout.Tab tab) { public void onTabReselected(TabLayout.Tab tab) {}
}
}); });
// 默认选择第一个标签
TabLayout.Tab firstTab = vb.homeTabLayout.getTabAt(0); TabLayout.Tab firstTab = vb.homeTabLayout.getTabAt(0);
if (firstTab != null) { if (firstTab != null) {
firstTab.select(); firstTab.select();
updateTabIcon(firstTab, true); updateTabIcon(firstTab, true);
} }
}
vb.circularProgressBar.setMaxProgress(100); // 假设最大值为100 private void setupProgressBar() {
vb.circularProgressBar.setMaxProgress(100);
vb.circularProgressBar.setOnProgressChangeListener(new CircularProgressBar.OnProgressChangeListener() { vb.circularProgressBar.setOnProgressChangeListener((progressBar, progress) -> {
@Override if (isBound && musicService != null) {
public void onProgressChanged(CircularProgressBar progressBar, int progress) { musicService.seekTo((int) ((progress / 100.0) * musicService.getDuration()));
viewModel.seekTo(progress); // 当用户改变进度时调用 ViewModel 方法
} }
}); });
}
private void setupPauseButton() {
vb.pause.setOnClickListener(v -> { vb.pause.setOnClickListener(v -> {
viewModel.togglePlay(); if (isBound && musicService != null) {
if (Boolean.TRUE.equals(musicService.getIsPlaying().getValue())) {
musicService.pauseAudio();
} else {
musicService.resumeAudio();
}
}
}); });
} }
private void setupObservers() { private void setupObservers() {
viewModel.getCurrentTime().observe(this, currentTime -> { if (musicService == null || isBound == false) return; // 确保只在服务绑定时设置观察者
vb.bottomText.setText(currentTime);
});
viewModel.getTotalTime().observe(this, totalTime -> { musicService.getIsPlaying().observe(this, isPlaying -> {
vb.topText.setText(totalTime); if (isPlaying != null) {
}); vb.pause.setImageResource(isPlaying ? R.drawable.pause : R.drawable.play);
if (isPlaying) {
viewModel.getProgress().observe(this, progress -> { startUpdatingProgress(); // 只有在播放时才开始更新进度
if (progress >= 0 && progress <= 100) { } else {
vb.circularProgressBar.setProgress(progress); // 更新进度条 stopUpdatingProgress(); // 暂停更新
} else { }
Log.e("A_HomeActivity", "Progress out of range: " + progress);
} }
}); });
}
viewModel.isPlaying().observe(this, isPlaying -> {
vb.pause.setImageResource(isPlaying ? R.drawable.play : R.drawable.pause); private void startUpdatingProgress() {
}); if (progressHandler != null) return; // 确保只有一个 Handler 在工作
progressHandler = new Handler(Looper.getMainLooper());
progressHandler.postDelayed(updateProgressRunnable, 1000);
}
private void stopUpdatingProgress() {
if (progressHandler != null) {
progressHandler.removeCallbacks(updateProgressRunnable);
progressHandler = null;
}
}
private final Runnable updateProgressRunnable = new Runnable() {
@Override
public void run() {
if (isBound && musicService != null && Boolean.TRUE.equals(musicService.getIsPlaying().getValue())) {
updateProgressAndDuration();
progressHandler.postDelayed(this, 1000);
}
}
};
private void updateProgressAndDuration() {
int currentPosition = musicService.getCurrentPosition();
int duration = musicService.getDuration();
if (duration > 0) {
vb.circularProgressBar.setProgress((int) ((currentPosition / (float) duration) * 100));
vb.bottomText.setText(formatTime(currentPosition));
vb.topText.setText(formatTime(duration));
}
}
private String formatTime(int milliseconds) {
int minutes = (milliseconds / 1000) / 60;
int seconds = (milliseconds / 1000) % 60;
return String.format(Locale.getDefault(), "%d:%02d", minutes, seconds);
} }
private void updateTabIcon(TabLayout.Tab tab, boolean isSelected) { private void updateTabIcon(TabLayout.Tab tab, boolean isSelected) {
HomeTabCustomBinding tabBinding = HomeTabCustomBinding.bind(Objects.requireNonNull(tab.getCustomView())); View customView = tab.getCustomView();
int position = tab.getPosition(); if (customView != null) {
tabBinding.homeIcon.setImageResource(isSelected ? selectedIcons[position] : defaultIcons[position]); HomeTabCustomBinding tabBinding = HomeTabCustomBinding.bind(customView);
tabBinding.homeIcon.setImageResource(isSelected ? selectedIcons[tab.getPosition()] : defaultIcons[tab.getPosition()]);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isBound) {
unbindService(serviceConnection);
isBound = false;
}
stopUpdatingProgress(); // 确保停止更新进度
} }
@Override @Override
public void onClick(View v) { public void onClick(View v) {
// Handle additional click events if needed
} }
} }

View File

@ -4,7 +4,9 @@ import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
@ -13,12 +15,14 @@ import com.hi.music.player.databinding.ActivityAplayBinding;
import com.hi.music.player.javabean.A_data.AudioItem; import com.hi.music.player.javabean.A_data.AudioItem;
import com.hi.music.player.service.MusicPlayerForegroundService; import com.hi.music.player.service.MusicPlayerForegroundService;
import java.lang.ref.WeakReference;
import java.util.Locale; import java.util.Locale;
public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> { public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
private MusicPlayerForegroundService musicService; private MusicPlayerForegroundService musicService;
private boolean isBound = false; private boolean isBound = false;
private Handler progressHandler;
private final ServiceConnection serviceConnection = new ServiceConnection() { private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override @Override
@ -27,12 +31,10 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
musicService = binder.getService(); musicService = binder.getService();
isBound = true; isBound = true;
// 观察服务中的播放状态 // 只设置一次观察者
musicService.getIsPlaying().observe(A_PlayActivity.this, isPlaying -> { musicService.getIsPlaying().observe(A_PlayActivity.this, this::updatePlayButton);
vb.playButton.setBackgroundResource(isPlaying ? R.drawable.play : R.drawable.pause); musicService.getFileName().observe(A_PlayActivity.this, vb.songTitle::setText);
});
// 更新进度和总时长
startUpdatingProgress(); startUpdatingProgress();
} }
@ -40,6 +42,12 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
isBound = false; isBound = false;
} }
private void updatePlayButton(Boolean isPlaying) {
if (isPlaying != null) {
vb.playButton.setBackgroundResource(isPlaying ? R.drawable.pause : R.drawable.play);
}
}
}; };
@Override @Override
@ -52,29 +60,13 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
Intent intent = getIntent(); Intent intent = getIntent();
AudioItem audioItem = (AudioItem) intent.getSerializableExtra("Path"); AudioItem audioItem = (AudioItem) intent.getSerializableExtra("Path");
if (audioItem == null) { if (audioItem == null) {
finish(); // 如果没有音频项目结束活动 finish();
return; return;
} }
// 启动前台服务 startMusicService(audioItem.getFile());
Intent serviceIntent = new Intent(this, MusicPlayerForegroundService.class); setupPlayButtonClickListener();
serviceIntent.putExtra("Path", audioItem.getFile()); vb.songSeekbar.setOnSeekBarChangeListener(new SeekBarListener());
Log.d("A_PlayActivity", "Path: " + audioItem.getFile());
startService(serviceIntent);
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
vb.playButton.setOnClickListener(v -> {
if (isBound) {
if (musicService.getIsPlaying().getValue() != null && musicService.getIsPlaying().getValue()) {
musicService.pauseAudio();
} else {
musicService.resumeAudio();
}
}
});
// 启动定期更新播放进度
startUpdatingProgress();
} }
@Override @Override
@ -82,25 +74,51 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
} }
private void startUpdatingProgress() { private void startMusicService(String path) {
new Thread(() -> { Intent serviceIntent = new Intent(this, MusicPlayerForegroundService.class);
while (isBound && musicService != null) { serviceIntent.putExtra("Path", path);
if (musicService.getIsPlaying().getValue() != null && musicService.getIsPlaying().getValue()) { Log.d("A_PlayActivity", "Path: " + path);
int currentPosition = musicService.getCurrentPosition(); // 获取当前播放位置 startService(serviceIntent);
int duration = musicService.getDuration(); // 获取总时长 bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
runOnUiThread(() -> { }
vb.songSeekbar.setProgress((int) ((currentPosition / (float) duration) * 100)); // 更新进度条
vb.current.setText(formatTime(currentPosition)); // 更新当前时间文本 private void setupPlayButtonClickListener() {
vb.time.setText(formatTime(duration)); // 更新总时间文本 vb.playButton.setOnClickListener(v -> {
}); if (isBound && musicService != null) {
} if (Boolean.TRUE.equals(musicService.getIsPlaying().getValue())) {
try { musicService.pauseAudio();
Thread.sleep(1000); // 每秒更新一次 } else {
} catch (InterruptedException e) { musicService.resumeAudio();
Thread.currentThread().interrupt();
} }
} }
}).start(); });
vb.backButton.setOnClickListener(v -> finish());
}
private void startUpdatingProgress() {
if (progressHandler == null) {
progressHandler = new Handler(Looper.getMainLooper());
progressHandler.postDelayed(new Runnable() {
@Override
public void run() {
updateSeekBarAndTime();
progressHandler.postDelayed(this, 1000);
}
}, 1000);
}
}
private void updateSeekBarAndTime() {
if (isBound && musicService != null && Boolean.TRUE.equals(musicService.getIsPlaying().getValue())) {
int currentPosition = musicService.getCurrentPosition();
int duration = musicService.getDuration();
if (duration > 0) {
vb.songSeekbar.setProgress((int) ((currentPosition / (float) duration) * 100));
vb.current.setText(formatTime(currentPosition));
vb.time.setText(formatTime(duration));
}
}
} }
private String formatTime(int milliseconds) { private String formatTime(int milliseconds) {
@ -116,6 +134,10 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
unbindService(serviceConnection); unbindService(serviceConnection);
isBound = false; isBound = false;
} }
if (progressHandler != null) {
progressHandler.removeCallbacksAndMessages(null);
progressHandler = null; // 释放引用
}
} }
@Override @Override
@ -132,4 +154,28 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
public void onClick(View v) { public void onClick(View v) {
// 处理其他点击事件 // 处理其他点击事件
} }
private class SeekBarListener implements android.widget.SeekBar.OnSeekBarChangeListener {
@Override
public void onProgressChanged(android.widget.SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser && musicService != null && isBound) {
int duration = musicService.getDuration();
if (duration > 0) {
int newPosition = (int) ((progress / 100.0) * duration);
musicService.seekTo(newPosition);
}
}
}
@Override
public void onStartTrackingTouch(android.widget.SeekBar seekBar) {
// 用户开始拖动进度条时触发
}
@Override
public void onStopTrackingTouch(android.widget.SeekBar seekBar) {
// 用户停止拖动进度条时触发
startUpdatingProgress(); // 拖动结束后重新启动进度更新
}
}
} }

View File

@ -1,130 +1,14 @@
package com.hi.music.player.ui.activity.viewmodel; package com.hi.music.player.ui.activity.viewmodel;
import android.app.Application; import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import com.hi.music.player.service.MusicPlayerForegroundService;
import java.util.Locale;
public class A_VMPlay extends AndroidViewModel { public class A_VMPlay extends AndroidViewModel {
private final MutableLiveData<String> currentTime = new MutableLiveData<>();
private final MutableLiveData<String> totalTime = new MutableLiveData<>();
private final MutableLiveData<String> fileName = new MutableLiveData<>();
private final MutableLiveData<Boolean> isPlaying = new MutableLiveData<>(false);
private final MutableLiveData<Integer> progress = new MutableLiveData<>(0); // 添加进度 LiveData
private MusicPlayerForegroundService musicService; public A_VMPlay(@NonNull Application application) {
private boolean isBound = false;
public A_VMPlay(Application application) {
super(application); super(application);
bindToMusicService();
}
// 获取进度的 LiveData
public LiveData<Integer> getProgress() {
return progress;
}
public LiveData<String> getCurrentTime() {
return currentTime;
}
public LiveData<String> getTotalTime() {
return totalTime;
}
public LiveData<Boolean> isPlaying() {
return isPlaying;
}
public LiveData<String> getFileName() {
return fileName;
}
private void bindToMusicService() {
Intent serviceIntent = new Intent(getApplication(), MusicPlayerForegroundService.class);
getApplication().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}
private final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicPlayerForegroundService.MusicBinder binder = (MusicPlayerForegroundService.MusicBinder) service;
musicService = binder.getService();
isBound = true;
// 观察服务中的播放状态
musicService.getIsPlaying().observeForever(isPlaying::setValue);
// 开始监听播放进度
startUpdatingProgress();
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
public void togglePlay() {
if (isBound) {
if (musicService.getIsPlaying().getValue() != null && musicService.getIsPlaying().getValue()) {
musicService.pauseAudio();
} else {
musicService.resumeAudio();
}
}
}
private void startUpdatingProgress() {
new Thread(() -> {
while (isBound && musicService != null) {
if (musicService.getIsPlaying().getValue() != null && musicService.getIsPlaying().getValue()) {
int currentPosition = musicService.getCurrentPosition(); // 从服务获取当前播放位置
currentTime.postValue(formatTime(currentPosition));
int duration = musicService.getDuration(); // 从服务获取音频总时长
progress.postValue((int) ((currentPosition / (float) duration) * 100)); // 更新进度
totalTime.postValue(formatTime(duration));
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
}
public void seekTo(int progress) {
if (isBound && musicService != null) {
int duration = musicService.getDuration();
musicService.seekTo((int) (duration * progress / 100.0));
}
}
private String formatTime(int milliseconds) {
int minutes = (milliseconds / 1000) / 60;
int seconds = (milliseconds / 1000) % 60;
return String.format(Locale.getDefault(), "%d:%02d", minutes, seconds);
}
@Override
protected void onCleared() {
super.onCleared();
if (isBound) {
getApplication().unbindService(serviceConnection);
isBound = false;
}
} }
} }

View File

@ -6,13 +6,21 @@
<path <path
android:pathData="M17,31.167C24.824,31.167 31.167,24.824 31.167,17C31.167,9.176 24.824,2.833 17,2.833C9.176,2.833 2.833,9.176 2.833,17C2.833,24.824 9.176,31.167 17,31.167Z" android:pathData="M17,31.167C24.824,31.167 31.167,24.824 31.167,17C31.167,9.176 24.824,2.833 17,2.833C9.176,2.833 2.833,9.176 2.833,17C2.833,24.824 9.176,31.167 17,31.167Z"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="1.66667" android:strokeWidth="2"
android:fillColor="#333333" android:fillColor="#333333"
android:strokeColor="#333333"/> android:strokeColor="#333333"/>
<path <path
android:pathData="M14.167,17V12.092L18.417,14.546L22.667,17L18.417,19.454L14.167,21.907V17Z" android:pathData="M13.458,12.75V21.25"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="1.66667" android:strokeWidth="2"
android:fillColor="#ffffff" android:fillColor="#00000000"
android:strokeColor="#ffffff"/> android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M20.542,12.75V21.25"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</vector> </vector>

View File

@ -6,11 +6,7 @@
<path <path
android:pathData="M11,0L19,0A11,11 0,0 1,30 11L30,11A11,11 0,0 1,19 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z" android:pathData="M11,0L19,0A11,11 0,0 1,30 11L30,11A11,11 0,0 1,19 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"
android:fillColor="#ffffff"/> android:fillColor="#ffffff"/>
<group> <path
<clip-path android:pathData="M15,17.714C14.682,17.714 14.377,17.594 14.151,17.38C13.926,17.165 13.8,16.875 13.8,16.571V5.143C13.8,4.84 13.926,4.549 14.151,4.335C14.377,4.12 14.682,4 15,4C15.318,4 15.623,4.12 15.849,4.335C16.074,4.549 16.2,4.84 16.2,5.143V16.571C16.2,16.875 16.074,17.165 15.849,17.38C15.623,17.594 15.318,17.714 15,17.714ZM10.2,15.429C9.882,15.429 9.577,15.308 9.351,15.094C9.126,14.88 9,14.589 9,14.286V8.571C9,8.268 9.127,7.978 9.352,7.763C9.577,7.549 9.882,7.429 10.2,7.429C10.518,7.429 10.823,7.549 11.049,7.763C11.274,7.978 11.4,8.268 11.4,8.571V14.286C11.4,14.436 11.369,14.584 11.309,14.723C11.248,14.862 11.16,14.988 11.049,15.094C10.937,15.2 10.805,15.284 10.659,15.342C10.514,15.399 10.358,15.429 10.2,15.429ZM19.8,15.429C19.482,15.429 19.177,15.308 18.951,15.094C18.726,14.88 18.6,14.589 18.6,14.286V8.571C18.6,8.268 18.726,7.978 18.951,7.763C19.177,7.549 19.482,7.429 19.8,7.429C20.118,7.429 20.423,7.549 20.649,7.763C20.874,7.978 21,8.268 21,8.571V14.286C21,14.589 20.874,14.88 20.649,15.094C20.424,15.308 20.118,15.429 19.8,15.429Z"
android:pathData="M10,5h12v12h-12z"/> android:fillColor="#231815"/>
<path
android:pathData="M20.1,8.874L14.584,5.392C14.204,5.152 13.766,5.019 13.317,5.006C12.868,4.993 12.424,5.1 12.03,5.317C11.637,5.534 11.308,5.853 11.08,6.239C10.851,6.626 10.73,7.067 10.73,7.517V14.483C10.73,14.933 10.851,15.374 11.08,15.761C11.308,16.147 11.637,16.466 12.03,16.683C12.424,16.9 12.868,17.007 13.317,16.994C13.766,16.981 14.204,16.848 14.584,16.608L20.1,13.126C20.458,12.899 20.753,12.585 20.958,12.214C21.163,11.842 21.27,11.424 21.27,11C21.27,10.576 21.163,10.158 20.958,9.786C20.753,9.415 20.458,9.101 20.1,8.874Z"
android:fillColor="#231815"/>
</group>
</vector> </vector>

View File

@ -9,14 +9,22 @@
<path <path
android:pathData="M10,18.333C14.602,18.333 18.333,14.602 18.333,10C18.333,5.398 14.602,1.667 10,1.667C5.398,1.667 1.667,5.398 1.667,10C1.667,14.602 5.398,18.333 10,18.333Z" android:pathData="M10,18.333C14.602,18.333 18.333,14.602 18.333,10C18.333,5.398 14.602,1.667 10,1.667C5.398,1.667 1.667,5.398 1.667,10C1.667,14.602 5.398,18.333 10,18.333Z"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="1.66667" android:strokeWidth="2"
android:fillColor="#333333" android:fillColor="#333333"
android:strokeColor="#333333"/> android:strokeColor="#333333"/>
<path <path
android:pathData="M8.333,10V7.113L10.833,8.557L13.333,10L10.833,11.443L8.333,12.887V10Z" android:pathData="M7.917,7.5V12.5"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="1.66667" android:strokeWidth="2"
android:fillColor="#151718" android:fillColor="#00000000"
android:strokeColor="#151718"/> android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
<path
android:pathData="M12.083,7.5V12.5"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</group> </group>
</vector> </vector>

View File

@ -6,21 +6,13 @@
<path <path
android:pathData="M17,31.167C24.824,31.167 31.167,24.824 31.167,17C31.167,9.176 24.824,2.833 17,2.833C9.176,2.833 2.833,9.176 2.833,17C2.833,24.824 9.176,31.167 17,31.167Z" android:pathData="M17,31.167C24.824,31.167 31.167,24.824 31.167,17C31.167,9.176 24.824,2.833 17,2.833C9.176,2.833 2.833,9.176 2.833,17C2.833,24.824 9.176,31.167 17,31.167Z"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="1.66667"
android:fillColor="#333333" android:fillColor="#333333"
android:strokeColor="#333333"/> android:strokeColor="#333333"/>
<path <path
android:pathData="M13.458,12.75V21.25" android:pathData="M14.167,17V12.092L18.417,14.546L22.667,17L18.417,19.454L14.167,21.907V17Z"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="1.66667"
android:fillColor="#00000000" android:fillColor="#ffffff"
android:strokeColor="#ffffff" android:strokeColor="#ffffff"/>
android:strokeLineCap="round"/>
<path
android:pathData="M20.542,12.75V21.25"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</vector> </vector>

View File

@ -6,7 +6,11 @@
<path <path
android:pathData="M11,0L19,0A11,11 0,0 1,30 11L30,11A11,11 0,0 1,19 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z" android:pathData="M11,0L19,0A11,11 0,0 1,30 11L30,11A11,11 0,0 1,19 22L11,22A11,11 0,0 1,0 11L0,11A11,11 0,0 1,11 0z"
android:fillColor="#ffffff"/> android:fillColor="#ffffff"/>
<path <group>
android:pathData="M15,17.714C14.682,17.714 14.377,17.594 14.151,17.38C13.926,17.165 13.8,16.875 13.8,16.571V5.143C13.8,4.84 13.926,4.549 14.151,4.335C14.377,4.12 14.682,4 15,4C15.318,4 15.623,4.12 15.849,4.335C16.074,4.549 16.2,4.84 16.2,5.143V16.571C16.2,16.875 16.074,17.165 15.849,17.38C15.623,17.594 15.318,17.714 15,17.714ZM10.2,15.429C9.882,15.429 9.577,15.308 9.351,15.094C9.126,14.88 9,14.589 9,14.286V8.571C9,8.268 9.127,7.978 9.352,7.763C9.577,7.549 9.882,7.429 10.2,7.429C10.518,7.429 10.823,7.549 11.049,7.763C11.274,7.978 11.4,8.268 11.4,8.571V14.286C11.4,14.436 11.369,14.584 11.309,14.723C11.248,14.862 11.16,14.988 11.049,15.094C10.937,15.2 10.805,15.284 10.659,15.342C10.514,15.399 10.358,15.429 10.2,15.429ZM19.8,15.429C19.482,15.429 19.177,15.308 18.951,15.094C18.726,14.88 18.6,14.589 18.6,14.286V8.571C18.6,8.268 18.726,7.978 18.951,7.763C19.177,7.549 19.482,7.429 19.8,7.429C20.118,7.429 20.423,7.549 20.649,7.763C20.874,7.978 21,8.268 21,8.571V14.286C21,14.589 20.874,14.88 20.649,15.094C20.424,15.308 20.118,15.429 19.8,15.429Z" <clip-path
android:fillColor="#231815"/> android:pathData="M10,5h12v12h-12z"/>
<path
android:pathData="M20.1,8.874L14.584,5.392C14.204,5.152 13.766,5.019 13.317,5.006C12.868,4.993 12.424,5.1 12.03,5.317C11.637,5.534 11.308,5.853 11.08,6.239C10.851,6.626 10.73,7.067 10.73,7.517V14.483C10.73,14.933 10.851,15.374 11.08,15.761C11.308,16.147 11.637,16.466 12.03,16.683C12.424,16.9 12.868,17.007 13.317,16.994C13.766,16.981 14.204,16.848 14.584,16.608L20.1,13.126C20.458,12.899 20.753,12.585 20.958,12.214C21.163,11.842 21.27,11.424 21.27,11C21.27,10.576 21.163,10.158 20.958,9.786C20.753,9.415 20.458,9.101 20.1,8.874Z"
android:fillColor="#231815"/>
</group>
</vector> </vector>

View File

@ -9,22 +9,14 @@
<path <path
android:pathData="M10,18.333C14.602,18.333 18.333,14.602 18.333,10C18.333,5.398 14.602,1.667 10,1.667C5.398,1.667 1.667,5.398 1.667,10C1.667,14.602 5.398,18.333 10,18.333Z" android:pathData="M10,18.333C14.602,18.333 18.333,14.602 18.333,10C18.333,5.398 14.602,1.667 10,1.667C5.398,1.667 1.667,5.398 1.667,10C1.667,14.602 5.398,18.333 10,18.333Z"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="1.66667"
android:fillColor="#333333" android:fillColor="#333333"
android:strokeColor="#333333"/> android:strokeColor="#333333"/>
<path <path
android:pathData="M7.917,7.5V12.5" android:pathData="M8.333,10V7.113L10.833,8.557L13.333,10L10.833,11.443L8.333,12.887V10Z"
android:strokeLineJoin="round" android:strokeLineJoin="round"
android:strokeWidth="2" android:strokeWidth="1.66667"
android:fillColor="#00000000" android:fillColor="#151718"
android:strokeColor="#ffffff" android:strokeColor="#151718"/>
android:strokeLineCap="round"/>
<path
android:pathData="M12.083,7.5V12.5"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ffffff"
android:strokeLineCap="round"/>
</group> </group>
</vector> </vector>

View File

@ -12,7 +12,7 @@
android:id="@+id/home_viewpager" android:id="@+id/home_viewpager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/home_tab_layout" app:layout_constraintBottom_toTopOf="@+id/home_container"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
@ -22,7 +22,8 @@
android:background="@drawable/a_rounded_rectangle_tab_layout" android:background="@drawable/a_rounded_rectangle_tab_layout"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:tabIndicatorHeight="0dp" app:tabIndicatorHeight="0dp"
app:tabRippleColor="@android:color/transparent" /> app:tabRippleColor="@android:color/transparent"
tools:layout_editor_absoluteX="0dp" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/home_container" android:id="@+id/home_container"
@ -102,7 +103,7 @@
android:layout_width="34dp" android:layout_width="34dp"
android:layout_height="34dp" android:layout_height="34dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:src="@drawable/pause" android:src="@drawable/play"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />

View File

@ -56,7 +56,7 @@
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:src="@drawable/pause_flat" /> android:src="@drawable/play_flat" />
</LinearLayout> </LinearLayout>

View File

@ -54,7 +54,7 @@
android:layout_width="20dp" android:layout_width="20dp"
android:layout_height="20dp" android:layout_height="20dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:src="@drawable/pause_shadow" android:src="@drawable/play_shadow"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />