A面前台播放优化
This commit is contained in:
parent
129680cb45
commit
90564a274c
@ -7,6 +7,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
@ -43,6 +44,9 @@ public class A_InstrumentAdapter extends RecyclerView.Adapter<A_InstrumentAdapte
|
||||
|
||||
Log.d("------","--------"+audioItem.getImage());
|
||||
|
||||
holder.textView1.setText(audioItem.getName());
|
||||
holder.textView2.setText(audioItem.getName());
|
||||
|
||||
Glide.with(context)
|
||||
.load("file:///android_asset/" + audioItem.getImage()) // 正确的路径
|
||||
.into(holder.imageView);
|
||||
@ -75,11 +79,15 @@ public class A_InstrumentAdapter extends RecyclerView.Adapter<A_InstrumentAdapte
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ImageView imageView;
|
||||
ImageView imageView;
|
||||
TextView textView1;
|
||||
TextView textView2;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.background_image);
|
||||
textView1 = itemView.findViewById(R.id.title);
|
||||
textView2 = itemView.findViewById(R.id.time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
@ -40,6 +41,8 @@ public class A_NatureAdapter extends RecyclerView.Adapter<A_NatureAdapter.ViewHo
|
||||
|
||||
AudioItem audioItem = audioItems.get(position);
|
||||
|
||||
holder.textView1.setText(audioItem.getName());
|
||||
holder.textView2.setText(audioItem.getName());
|
||||
|
||||
Glide.with(context)
|
||||
.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 {
|
||||
|
||||
private ImageView imageView;
|
||||
ImageView imageView;
|
||||
TextView textView1;
|
||||
TextView textView2;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
|
||||
imageView = itemView.findViewById(R.id.cover);
|
||||
textView1 = itemView.findViewById(R.id.title);
|
||||
textView2 = itemView.findViewById(R.id.time);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
@ -43,6 +44,8 @@ public class A_WhiteAdapter extends RecyclerView.Adapter<A_WhiteAdapter.ViewHold
|
||||
|
||||
Log.d("------","--------"+audioItem.getImage());
|
||||
|
||||
holder.textView1.setText(audioItem.getName());
|
||||
holder.textView2.setText(audioItem.getName());
|
||||
|
||||
// 加载图片,确保不使用 file:// 前缀,并将路径传递给 Glide
|
||||
Glide.with(context)
|
||||
@ -77,12 +80,16 @@ public class A_WhiteAdapter extends RecyclerView.Adapter<A_WhiteAdapter.ViewHold
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private ImageView imageView;
|
||||
ImageView imageView;
|
||||
TextView textView1;
|
||||
TextView textView2;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
|
||||
imageView = itemView.findViewById(R.id.image);
|
||||
textView1 = itemView.findViewById(R.id.title);
|
||||
textView2 = itemView.findViewById(R.id.time);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.media.MediaPlayer;
|
||||
@ -13,154 +12,248 @@ import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.hi.music.player.R;
|
||||
import com.hi.music.player.ui.activity.A_PlayActivity;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class MusicPlayerForegroundService extends Service {
|
||||
|
||||
// 通知渠道ID,用于创建通知渠道
|
||||
public static final String CHANNEL_ID = "MusicPlayerChannel";
|
||||
private MediaPlayer mediaPlayer;
|
||||
private final IBinder binder = new MusicBinder();
|
||||
private MutableLiveData<Boolean> isPlaying = new MutableLiveData<>(false);
|
||||
private MediaPlayer mediaPlayer; // MediaPlayer实例,用于播放音频
|
||||
private final IBinder binder = new MusicBinder(); // 用于绑定服务的Binder
|
||||
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 MusicPlayerForegroundService getService() {
|
||||
return MusicPlayerForegroundService.this;
|
||||
return MusicPlayerForegroundService.this; // 返回当前服务实例
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return binder;
|
||||
return binder; // 返回用于绑定服务的Binder
|
||||
}
|
||||
|
||||
// 当服务启动时调用该方法
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String audioPath = intent.getStringExtra("Path");
|
||||
if (audioPath != null) {
|
||||
initializePlayer(audioPath);
|
||||
// 从Intent中获取传入的音频路径
|
||||
String newAudioPath = intent.getStringExtra("Path");
|
||||
|
||||
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"));
|
||||
|
||||
return START_NOT_STICKY;
|
||||
// 启动前台服务并显示通知
|
||||
startForeground(1, createNotification());
|
||||
return START_NOT_STICKY; // 返回START_NOT_STICKY,表示服务不会在被系统杀死后自动重启
|
||||
}
|
||||
|
||||
private Notification createNotification(String title, String content) {
|
||||
createNotificationChannel();
|
||||
// 创建通知,用于前台服务显示
|
||||
private Notification createNotification() {
|
||||
createNotificationChannel(); // 创建通知渠道(适用于Android O及以上版本)
|
||||
|
||||
// 创建点击通知时打开的Intent
|
||||
Intent notificationIntent = new Intent(this, A_PlayActivity.class);
|
||||
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);
|
||||
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)
|
||||
.setContentTitle(title)
|
||||
.setContentText(content)
|
||||
.setSmallIcon(R.drawable.home_select)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setContentTitle("Playing Audio") // 通知标题
|
||||
.setContentText("Your audio is playing") // 通知内容
|
||||
.setSmallIcon(R.drawable.home_select) // 通知的小图标
|
||||
.setContentIntent(pendingIntent) // 点击通知后的Intent
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW) // 低优先级,避免干扰用户
|
||||
.build();
|
||||
}
|
||||
|
||||
// 创建通知渠道,适用于Android O及以上版本
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel serviceChannel = new NotificationChannel(
|
||||
CHANNEL_ID, "Music Player Channel", NotificationManager.IMPORTANCE_LOW);
|
||||
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) {
|
||||
try {
|
||||
Log.d("MediaPlayerError","path: "+path);
|
||||
Log.d("MusicPlayerService", "正在初始化播放器,音频路径: " + path);
|
||||
|
||||
if (mediaPlayer == null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
} else {
|
||||
mediaPlayer.reset();
|
||||
mediaPlayer = new MediaPlayer(); // 如果MediaPlayer为空,则创建一个新的实例
|
||||
}
|
||||
|
||||
if (path.startsWith("content://")) {
|
||||
Uri contentUri = Uri.parse(path);
|
||||
ContentResolver contentResolver = getContentResolver();
|
||||
AssetFileDescriptor afd = contentResolver.openAssetFileDescriptor(contentUri, "r");
|
||||
if (afd != null) {
|
||||
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
|
||||
afd.close();
|
||||
// 设置当前播放的文件名
|
||||
fileName.setValue(getFileNameFromPath(path));
|
||||
|
||||
// 根据传入的音频路径类型设置数据源
|
||||
setDataSource(path);
|
||||
|
||||
mediaPlayer.prepareAsync(); // 异步准备播放器
|
||||
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());
|
||||
afd.close();
|
||||
}
|
||||
|
||||
mediaPlayer.prepare();
|
||||
mediaPlayer.setOnPreparedListener(mp -> mediaPlayer.start());
|
||||
isPlaying.postValue(true);
|
||||
} catch (IOException e) {
|
||||
Log.e("MediaPlayerError", "Could not open file: " + path, 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() {
|
||||
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
|
||||
mediaPlayer.pause();
|
||||
isPlaying.postValue(false);
|
||||
mediaPlayer.pause(); // 如果当前正在播放,则暂停音频
|
||||
isPlaying.postValue(false); // 更新播放状态为“暂停”
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复音频播放
|
||||
public void resumeAudio() {
|
||||
if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
|
||||
mediaPlayer.start();
|
||||
isPlaying.postValue(true);
|
||||
mediaPlayer.start(); // 如果当前未播放,则恢复音频播放
|
||||
isPlaying.postValue(true); // 更新播放状态为“播放中”
|
||||
}
|
||||
}
|
||||
|
||||
// 获取当前播放状态
|
||||
public MutableLiveData<Boolean> getIsPlaying() {
|
||||
return isPlaying;
|
||||
}
|
||||
|
||||
// 添加获取当前播放位置的方法
|
||||
// 获取当前播放的文件名
|
||||
public MutableLiveData<String> getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
// 获取当前播放位置(毫秒)
|
||||
public int getCurrentPosition() {
|
||||
if (mediaPlayer != null) {
|
||||
return mediaPlayer.getCurrentPosition();
|
||||
}
|
||||
return 0; // 如果 mediaPlayer 为 null,返回 0
|
||||
return mediaPlayer != null ? mediaPlayer.getCurrentPosition() : 0;
|
||||
}
|
||||
|
||||
// 添加获取总时长的方法
|
||||
// 获取音频总时长(毫秒)
|
||||
public int getDuration() {
|
||||
if (mediaPlayer != null) {
|
||||
return mediaPlayer.getDuration();
|
||||
}
|
||||
return 0; // 如果 mediaPlayer 为 null,返回 0
|
||||
return mediaPlayer != null ? mediaPlayer.getDuration() : 0;
|
||||
}
|
||||
|
||||
// 跳转到指定播放位置
|
||||
public void seekTo(int position) {
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.seekTo(position);
|
||||
mediaPlayer.seekTo(position); // 将播放器跳转到指定位置
|
||||
}
|
||||
}
|
||||
|
||||
// 当服务销毁时释放MediaPlayer资源
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
mediaPlayer.release(); // 释放MediaPlayer资源
|
||||
mediaPlayer = null; // 将播放器设置为null,防止再次使用
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,35 +1,48 @@
|
||||
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.View;
|
||||
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import com.hi.music.player.R;
|
||||
import com.hi.music.player.adapter.A_HomeViewPagerAdapter;
|
||||
import com.hi.music.player.databinding.ActivityAhomeBinding;
|
||||
import com.hi.music.player.databinding.HomeTabCustomBinding;
|
||||
import com.hi.music.player.helper.CircularProgressBar;
|
||||
import com.hi.music.player.ui.activity.viewmodel.A_VMPlay;
|
||||
import com.hi.music.player.service.MusicPlayerForegroundService;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Locale;
|
||||
|
||||
public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
|
||||
|
||||
private final int[] defaultIcons = {
|
||||
R.drawable.home_unselect,
|
||||
R.drawable.import_unselect,
|
||||
};
|
||||
private final int[] defaultIcons = { R.drawable.home_unselect, R.drawable.import_unselect };
|
||||
private final int[] selectedIcons = { R.drawable.home_select, R.drawable.import_select };
|
||||
|
||||
private final int[] selectedIcons = {
|
||||
R.drawable.home_select,
|
||||
R.drawable.import_select,
|
||||
};
|
||||
private MusicPlayerForegroundService musicService;
|
||||
private boolean isBound = false;
|
||||
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
|
||||
protected ActivityAhomeBinding getViewBinding() {
|
||||
@ -38,9 +51,10 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
|
||||
|
||||
@Override
|
||||
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();
|
||||
setupObservers();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -50,7 +64,7 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
|
||||
|
||||
@Override
|
||||
public boolean isFullScreen() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -58,11 +72,20 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void initData() {
|
||||
private void initData() {
|
||||
setupViewPager();
|
||||
setupTabLayout();
|
||||
setupProgressBar();
|
||||
setupPauseButton();
|
||||
}
|
||||
|
||||
private void setupViewPager() {
|
||||
A_HomeViewPagerAdapter adapter = new A_HomeViewPagerAdapter(this);
|
||||
vb.homeViewpager.setAdapter(adapter);
|
||||
vb.homeViewpager.setUserInputEnabled(false);
|
||||
}
|
||||
|
||||
private void setupTabLayout() {
|
||||
new TabLayoutMediator(vb.homeTabLayout, vb.homeViewpager, (tab, position) -> {
|
||||
HomeTabCustomBinding tabBinding = HomeTabCustomBinding.inflate(LayoutInflater.from(this));
|
||||
tab.setCustomView(tabBinding.getRoot());
|
||||
@ -81,60 +104,112 @@ public class A_HomeActivity extends BaseActivity<ActivityAhomeBinding> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
}
|
||||
public void onTabReselected(TabLayout.Tab tab) {}
|
||||
});
|
||||
|
||||
// 默认选择第一个标签
|
||||
TabLayout.Tab firstTab = vb.homeTabLayout.getTabAt(0);
|
||||
if (firstTab != null) {
|
||||
firstTab.select();
|
||||
updateTabIcon(firstTab, true);
|
||||
}
|
||||
}
|
||||
|
||||
vb.circularProgressBar.setMaxProgress(100); // 假设最大值为100
|
||||
|
||||
vb.circularProgressBar.setOnProgressChangeListener(new CircularProgressBar.OnProgressChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(CircularProgressBar progressBar, int progress) {
|
||||
viewModel.seekTo(progress); // 当用户改变进度时,调用 ViewModel 方法
|
||||
private void setupProgressBar() {
|
||||
vb.circularProgressBar.setMaxProgress(100);
|
||||
vb.circularProgressBar.setOnProgressChangeListener((progressBar, progress) -> {
|
||||
if (isBound && musicService != null) {
|
||||
musicService.seekTo((int) ((progress / 100.0) * musicService.getDuration()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setupPauseButton() {
|
||||
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() {
|
||||
viewModel.getCurrentTime().observe(this, currentTime -> {
|
||||
vb.bottomText.setText(currentTime);
|
||||
});
|
||||
if (musicService == null || isBound == false) return; // 确保只在服务绑定时设置观察者
|
||||
|
||||
viewModel.getTotalTime().observe(this, totalTime -> {
|
||||
vb.topText.setText(totalTime);
|
||||
});
|
||||
|
||||
viewModel.getProgress().observe(this, progress -> {
|
||||
if (progress >= 0 && progress <= 100) {
|
||||
vb.circularProgressBar.setProgress(progress); // 更新进度条
|
||||
musicService.getIsPlaying().observe(this, isPlaying -> {
|
||||
if (isPlaying != null) {
|
||||
vb.pause.setImageResource(isPlaying ? R.drawable.pause : R.drawable.play);
|
||||
if (isPlaying) {
|
||||
startUpdatingProgress(); // 只有在播放时才开始更新进度
|
||||
} else {
|
||||
Log.e("A_HomeActivity", "Progress out of range: " + progress);
|
||||
stopUpdatingProgress(); // 暂停更新
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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) {
|
||||
HomeTabCustomBinding tabBinding = HomeTabCustomBinding.bind(Objects.requireNonNull(tab.getCustomView()));
|
||||
int position = tab.getPosition();
|
||||
tabBinding.homeIcon.setImageResource(isSelected ? selectedIcons[position] : defaultIcons[position]);
|
||||
View customView = tab.getCustomView();
|
||||
if (customView != null) {
|
||||
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
|
||||
public void onClick(View v) {
|
||||
|
||||
// Handle additional click events if needed
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,7 +4,9 @@ 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.util.Log;
|
||||
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.service.MusicPlayerForegroundService;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Locale;
|
||||
|
||||
public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
|
||||
|
||||
private MusicPlayerForegroundService musicService;
|
||||
private boolean isBound = false;
|
||||
private Handler progressHandler;
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
@ -27,12 +31,10 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
|
||||
musicService = binder.getService();
|
||||
isBound = true;
|
||||
|
||||
// 观察服务中的播放状态
|
||||
musicService.getIsPlaying().observe(A_PlayActivity.this, isPlaying -> {
|
||||
vb.playButton.setBackgroundResource(isPlaying ? R.drawable.play : R.drawable.pause);
|
||||
});
|
||||
// 只设置一次观察者
|
||||
musicService.getIsPlaying().observe(A_PlayActivity.this, this::updatePlayButton);
|
||||
musicService.getFileName().observe(A_PlayActivity.this, vb.songTitle::setText);
|
||||
|
||||
// 更新进度和总时长
|
||||
startUpdatingProgress();
|
||||
}
|
||||
|
||||
@ -40,6 +42,12 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
isBound = false;
|
||||
}
|
||||
|
||||
private void updatePlayButton(Boolean isPlaying) {
|
||||
if (isPlaying != null) {
|
||||
vb.playButton.setBackgroundResource(isPlaying ? R.drawable.pause : R.drawable.play);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
@ -52,29 +60,13 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
|
||||
Intent intent = getIntent();
|
||||
AudioItem audioItem = (AudioItem) intent.getSerializableExtra("Path");
|
||||
if (audioItem == null) {
|
||||
finish(); // 如果没有音频项目,结束活动
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动前台服务
|
||||
Intent serviceIntent = new Intent(this, MusicPlayerForegroundService.class);
|
||||
serviceIntent.putExtra("Path", audioItem.getFile());
|
||||
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();
|
||||
startMusicService(audioItem.getFile());
|
||||
setupPlayButtonClickListener();
|
||||
vb.songSeekbar.setOnSeekBarChangeListener(new SeekBarListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,25 +74,51 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
|
||||
|
||||
}
|
||||
|
||||
private void startUpdatingProgress() {
|
||||
new Thread(() -> {
|
||||
while (isBound && musicService != null) {
|
||||
if (musicService.getIsPlaying().getValue() != null && musicService.getIsPlaying().getValue()) {
|
||||
int currentPosition = musicService.getCurrentPosition(); // 获取当前播放位置
|
||||
int duration = musicService.getDuration(); // 获取总时长
|
||||
runOnUiThread(() -> {
|
||||
vb.songSeekbar.setProgress((int) ((currentPosition / (float) duration) * 100)); // 更新进度条
|
||||
vb.current.setText(formatTime(currentPosition)); // 更新当前时间文本
|
||||
vb.time.setText(formatTime(duration)); // 更新总时间文本
|
||||
private void startMusicService(String path) {
|
||||
Intent serviceIntent = new Intent(this, MusicPlayerForegroundService.class);
|
||||
serviceIntent.putExtra("Path", path);
|
||||
Log.d("A_PlayActivity", "Path: " + path);
|
||||
startService(serviceIntent);
|
||||
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
private void setupPlayButtonClickListener() {
|
||||
vb.playButton.setOnClickListener(v -> {
|
||||
if (isBound && musicService != null) {
|
||||
if (Boolean.TRUE.equals(musicService.getIsPlaying().getValue())) {
|
||||
musicService.pauseAudio();
|
||||
} else {
|
||||
musicService.resumeAudio();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
vb.backButton.setOnClickListener(v -> finish());
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000); // 每秒更新一次
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private String formatTime(int milliseconds) {
|
||||
@ -116,6 +134,10 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
|
||||
unbindService(serviceConnection);
|
||||
isBound = false;
|
||||
}
|
||||
if (progressHandler != null) {
|
||||
progressHandler.removeCallbacksAndMessages(null);
|
||||
progressHandler = null; // 释放引用
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -132,4 +154,28 @@ public class A_PlayActivity extends BaseActivity<ActivityAplayBinding> {
|
||||
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(); // 拖动结束后重新启动进度更新
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,130 +1,14 @@
|
||||
package com.hi.music.player.ui.activity.viewmodel;
|
||||
|
||||
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.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
|
||||
import com.hi.music.player.service.MusicPlayerForegroundService;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
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;
|
||||
private boolean isBound = false;
|
||||
|
||||
public A_VMPlay(Application application) {
|
||||
public A_VMPlay(@NonNull Application 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,13 +6,21 @@
|
||||
<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:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#333333"
|
||||
android:strokeColor="#333333"/>
|
||||
<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:strokeWidth="1.66667"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"/>
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
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>
|
||||
|
||||
@ -6,11 +6,7 @@
|
||||
<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:fillColor="#ffffff"/>
|
||||
<group>
|
||||
<clip-path
|
||||
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: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:fillColor="#231815"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
||||
@ -9,14 +9,22 @@
|
||||
<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:strokeLineJoin="round"
|
||||
android:strokeWidth="1.66667"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#333333"
|
||||
android:strokeColor="#333333"/>
|
||||
<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:strokeWidth="1.66667"
|
||||
android:fillColor="#151718"
|
||||
android:strokeColor="#151718"/>
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
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>
|
||||
</vector>
|
||||
|
||||
@ -6,21 +6,13 @@
|
||||
<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:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#333333"
|
||||
android:strokeColor="#333333"/>
|
||||
<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:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
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"/>
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#ffffff"/>
|
||||
</vector>
|
||||
|
||||
@ -6,7 +6,11 @@
|
||||
<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:fillColor="#ffffff"/>
|
||||
<group>
|
||||
<clip-path
|
||||
android:pathData="M10,5h12v12h-12z"/>
|
||||
<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="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>
|
||||
|
||||
@ -9,22 +9,14 @@
|
||||
<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:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#333333"
|
||||
android:strokeColor="#333333"/>
|
||||
<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:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
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"/>
|
||||
android:strokeWidth="1.66667"
|
||||
android:fillColor="#151718"
|
||||
android:strokeColor="#151718"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
android:id="@+id/home_viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/home_tab_layout"
|
||||
app:layout_constraintBottom_toTopOf="@+id/home_container"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
@ -22,7 +22,8 @@
|
||||
android:background="@drawable/a_rounded_rectangle_tab_layout"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:tabIndicatorHeight="0dp"
|
||||
app:tabRippleColor="@android:color/transparent" />
|
||||
app:tabRippleColor="@android:color/transparent"
|
||||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/home_container"
|
||||
@ -102,7 +103,7 @@
|
||||
android:layout_width="34dp"
|
||||
android:layout_height="34dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:src="@drawable/pause"
|
||||
android:src="@drawable/play"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:src="@drawable/pause_flat" />
|
||||
android:src="@drawable/play_flat" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:src="@drawable/pause_shadow"
|
||||
android:src="@drawable/play_shadow"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user