V1.0.0(4)优化
This commit is contained in:
parent
4831c39881
commit
c0f62a21f1
@ -11,7 +11,7 @@ android {
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.sound.prankparty.test"
|
||||
applicationId = "com.sound.prankparty"
|
||||
minSdk = 23
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
|
||||
@ -38,13 +38,13 @@
|
||||
<activity
|
||||
android:name=".Activity.AirHornActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".Activity.SplashActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.StartUp" />
|
||||
<activity
|
||||
android:name=".Activity.MainActivity"
|
||||
android:exported="true">
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".Activity.SplashActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.StartUp">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ public class NewRecordActivity extends AppCompatActivity {
|
||||
toggleRecording();
|
||||
} else {
|
||||
// 权限被拒绝,通知用户
|
||||
Toast.makeText(this, "录音权限被拒绝,请在设置中启用权限", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "The recording permission is denied. Enable the permission in the Settings", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,8 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
private AppDatabase appDatabase;
|
||||
private SaveSoundsDao saveSoundsDao;
|
||||
private int duration;
|
||||
// 添加一个布尔变量来标记是否保存
|
||||
private boolean isSaved = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@ -51,10 +53,20 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
// 获取传递过来的录音文件路径
|
||||
audioFilePath = getIntent().getStringExtra("audioFilePath");
|
||||
if (audioFilePath == null) {
|
||||
Toast.makeText(this, "音频文件路径无效", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "The audio file path is invalid", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Log.d("SaveRecordActivity", audioFilePath);
|
||||
|
||||
// 检查文件是否存在
|
||||
File audioFile = new File(audioFilePath);
|
||||
if (!audioFile.exists()) {
|
||||
Toast.makeText(this, "Audio file does not exist", Toast.LENGTH_SHORT).show();
|
||||
Log.e("SaveRecordActivity", "Audio file does not exist at path: " + audioFilePath);
|
||||
finish(); // 结束活动
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d("SaveRecordActivity", "Audio file path: " + audioFilePath);
|
||||
|
||||
// 初始化数据库和 DAO
|
||||
appDatabase = AppDatabase.getDatabase(this);
|
||||
@ -101,7 +113,7 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
inputText = binding.saveRecordName.getText().toString();
|
||||
//检测是否输入为空字符串
|
||||
if (inputText.trim().isEmpty()) {
|
||||
Toast.makeText(getApplicationContext(), "名称不能为空", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(getApplicationContext(), "The name cannot be empty", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -110,6 +122,9 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
new Thread(() -> {
|
||||
saveSoundsDao.insertSound(new SaveSounds(inputText, audioFilePath, datePart, timePart, formatTime(duration)));
|
||||
|
||||
// 设置isSaved为true,表示文件已保存
|
||||
isSaved = true;
|
||||
|
||||
runOnUiThread(() -> {
|
||||
Intent intent = new Intent(SaveRecordActivity.this, MainActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
@ -130,9 +145,17 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
File file = new File(audioFilePath);
|
||||
if (file.exists()) {
|
||||
boolean deleted = file.delete();
|
||||
if (deleted) {
|
||||
Log.d("SaveRecordActivity", "Deleted audio file: " + audioFilePath);
|
||||
} else {
|
||||
Log.e("SaveRecordActivity", "Failed to delete audio file: " + audioFilePath);
|
||||
}
|
||||
} else {
|
||||
Log.e("SaveRecordActivity", "Audio file does not exist, cannot delete: " + audioFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void clearFocusFromAllChildren(ViewGroup parent) {
|
||||
for (int i = 0; i < parent.getChildCount(); i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
@ -150,6 +173,7 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
|
||||
private void displayAudioDuration() {
|
||||
if (audioFilePath != null) {
|
||||
Log.d("SaveRecordActivity", "Attempting to display audio duration for: " + audioFilePath);
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioFilePath);
|
||||
@ -157,41 +181,49 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
|
||||
duration = mediaPlayer.getDuration();
|
||||
binding.saveRecordTime.setText(formatTime(duration));
|
||||
Log.d("SaveRecordActivity", "Audio duration: " + formatTime(duration));
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "无法加载音频", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "Unable to load audio", Toast.LENGTH_SHORT).show();
|
||||
Log.e("SaveRecordActivity", "IOException: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, "音频文件路径无效", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "The audio file path is invalid", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void playOrPauseAudio() {
|
||||
if (isPlaying) {
|
||||
mediaPlayer.pause();
|
||||
binding.saveRecordPlay.setImageResource(R.drawable.playback); // 更新按钮为播放图标
|
||||
isPlaying = false;
|
||||
Log.d("SaveRecordActivity", "Audio paused.");
|
||||
} else {
|
||||
if (mediaPlayer == null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioFilePath);
|
||||
mediaPlayer.prepare();
|
||||
Log.d("SaveRecordActivity", "Prepared media player for audio file: " + audioFilePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "无法播放音频", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "Unable to play audio", Toast.LENGTH_SHORT).show();
|
||||
Log.e("SaveRecordActivity", "IOException: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
mediaPlayer.start();
|
||||
binding.saveRecordPlay.setImageResource(R.drawable.pause); // 更新按钮为暂停图标
|
||||
isPlaying = true;
|
||||
Log.d("SaveRecordActivity", "Audio started playing.");
|
||||
|
||||
mediaPlayer.setOnCompletionListener(mp -> {
|
||||
Toast.makeText(this, "播放完成", Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(this, "Play completed", Toast.LENGTH_SHORT).show();
|
||||
binding.saveRecordPlay.setImageResource(R.drawable.playback); // 恢复播放图标
|
||||
isPlaying = false;
|
||||
Log.d("SaveRecordActivity", "Audio playback completed.");
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -206,7 +238,10 @@ public class SaveRecordActivity extends AppCompatActivity {
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
deleteRecordingFile();
|
||||
// 检查isSaved标志,如果为false则删除文件
|
||||
if (!isSaved) {
|
||||
deleteRecordingFile();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
|
||||
@ -76,26 +76,23 @@ public class SoundRecyclerViewAdapter extends RecyclerView.Adapter<SoundRecycler
|
||||
holder.textView.setText("");
|
||||
}
|
||||
|
||||
if (category != null) {
|
||||
Glide.with(MainApplication.getContext())
|
||||
//指定加载的资源类型为Drawable
|
||||
.asDrawable()
|
||||
//设置跳过内存缓存,即加载的图片不会存储在内存缓存中
|
||||
.skipMemoryCache(true)
|
||||
//设置磁盘缓存策略为DiskCacheStrategy.ALL,即缓存原始图片和转换后的图片
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(category.getCategoryUrl())
|
||||
.transform(new CenterCrop())
|
||||
.into(holder.imageView);
|
||||
|
||||
Glide.with(MainApplication.getContext())
|
||||
//指定加载的资源类型为Drawable
|
||||
.asDrawable()
|
||||
//设置跳过内存缓存,即加载的图片不会存储在内存缓存中
|
||||
.skipMemoryCache(true)
|
||||
//设置磁盘缓存策略为DiskCacheStrategy.ALL,即缓存原始图片和转换后的图片
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(category.getCategoryUrl())
|
||||
.transform(new CenterCrop())
|
||||
.into(holder.imageView);
|
||||
|
||||
holder.imageView.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(context, AirHornActivity.class);
|
||||
intent.putExtra("color", currentColor); // 添加颜色值到 Intent
|
||||
intent.putExtra("123",category);
|
||||
context.startActivity(intent);
|
||||
});
|
||||
}
|
||||
holder.imageView.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(context, AirHornActivity.class);
|
||||
intent.putExtra("color", currentColor); // 添加颜色值到 Intent
|
||||
intent.putExtra("123",category);
|
||||
context.startActivity(intent);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
package com.sound.prankparty.Application;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
public class MainApplication extends Application {
|
||||
/**
|
||||
* 全局的上下文
|
||||
*/
|
||||
private static Context mContext;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
//获取应用的上下文并赋值给 mContext
|
||||
mContext = getApplicationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取context
|
||||
* @return
|
||||
*/
|
||||
public static Context getContext(){
|
||||
return mContext;
|
||||
}
|
||||
|
||||
//重写 onLowMemory 方法,在系统内存不足时调用。这里只是调用了父类的 onLowMemory 方法,没有做其他处理
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,43 +0,0 @@
|
||||
package com.sound.prankparty.FirstFragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.sound.prankparty.JSON.Category;
|
||||
import com.sound.prankparty.JSON.SoundItem;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Utils.ItemDecoration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AirHornActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_airhonr);
|
||||
|
||||
RecyclerView recyclerView = findViewById(R.id.air_horn_recyclerview);
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(this, 2));
|
||||
|
||||
// 接收传递的 List<Category> 对象
|
||||
Category categories = (Category) getIntent().getSerializableExtra("123");
|
||||
|
||||
if (categories == null) {
|
||||
// 处理 categories 为 null 的情况
|
||||
return;
|
||||
}
|
||||
List<SoundItem> soundItemList = categories.getSoundItemList();
|
||||
|
||||
recyclerView.setAdapter(new AirHornRecyclerViewAdapter(this, soundItemList));
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰。
|
||||
ItemDecoration itemDecoration = new ItemDecoration(16, 19, 10);
|
||||
recyclerView.addItemDecoration(itemDecoration);
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,98 +0,0 @@
|
||||
package com.sound.prankparty.FirstFragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
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.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.sound.prankparty.Application.MainApplication;
|
||||
import com.sound.prankparty.JSON.SoundItem;
|
||||
import com.sound.prankparty.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AirHornRecyclerViewAdapter extends RecyclerView.Adapter<AirHornRecyclerViewAdapter.AirhonrViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private List<SoundItem> soundItemList;
|
||||
|
||||
public AirHornRecyclerViewAdapter(Context context, List<SoundItem> soundItemList) {
|
||||
this.context = context;
|
||||
this.soundItemList = soundItemList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AirhonrViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sound, parent, false);
|
||||
return new AirHornRecyclerViewAdapter.AirhonrViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull AirhonrViewHolder holder, int position) {
|
||||
|
||||
SoundItem soundItem = soundItemList.get(position);
|
||||
|
||||
String originalName = soundItem.getTitle();
|
||||
// 检查名称是否为空,以避免空指针异常
|
||||
if (originalName != null && !originalName.isEmpty()) {
|
||||
// // 将首字母大写
|
||||
// String capitalizedName = originalName.substring(0, 1).toUpperCase() + originalName.substring(1);
|
||||
// 设置文本字体
|
||||
holder.textView.setTypeface(Typeface.createFromAsset(context.getAssets(), "FrancoisOne-Regular.ttf"));
|
||||
//设置文本
|
||||
holder.textView.setText(originalName);
|
||||
} else {
|
||||
// 如果名称为空,可以设置一个默认值或者不设置
|
||||
holder.textView.setText("");
|
||||
}
|
||||
|
||||
if (soundItem != null) {
|
||||
Glide.with(MainApplication.getContext())
|
||||
//指定加载的资源类型为Drawable
|
||||
.asDrawable()
|
||||
//设置跳过内存缓存,即加载的图片不会存储在内存缓存中
|
||||
.skipMemoryCache(true)
|
||||
//设置磁盘缓存策略为DiskCacheStrategy.ALL,即缓存原始图片和转换后的图片
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(soundItem.getPreUrl())
|
||||
.transform(new CenterCrop())
|
||||
.into(holder.imageView);
|
||||
|
||||
holder.imageView.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(context, PlaySoundActivity.class);
|
||||
intent.putExtra("1234", soundItem);
|
||||
context.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return soundItemList.size();
|
||||
}
|
||||
|
||||
static class AirhonrViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
ImageView imageView;
|
||||
TextView textView;
|
||||
|
||||
public AirhonrViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.item_imageview_sound);
|
||||
textView = itemView.findViewById(R.id.item_textview_sound);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,257 +0,0 @@
|
||||
package com.sound.prankparty.FirstFragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.sound.prankparty.Application.MainApplication;
|
||||
import com.sound.prankparty.JSON.SoundItem;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.AppDatabase;
|
||||
import com.sound.prankparty.Room.FavoriteSounds;
|
||||
import com.sound.prankparty.Room.FavoriteSoundsDao;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class PlaySoundActivity extends AppCompatActivity {
|
||||
|
||||
private MediaPlayer mediaPlayer;
|
||||
private ImageView playBack;
|
||||
private SoundItem soundItemList;
|
||||
private ImageView imageView;
|
||||
private SeekBar seekBar;
|
||||
private AudioManager audioManager;
|
||||
private boolean isPlaying = false; // 默认未播放
|
||||
private ImageView loop;
|
||||
private boolean isLooping = false; // 默认不循环
|
||||
private TextView textView;
|
||||
private AppDatabase appDatabase;
|
||||
private FavoriteSoundsDao favoriteSoundsDao;
|
||||
private ImageView favorite;
|
||||
private boolean isFavorite = false; //默认不收藏
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_play_sound);
|
||||
|
||||
// 获取音频管理器
|
||||
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
// 获取控件实例
|
||||
imageView = findViewById(R.id.image);
|
||||
playBack = findViewById(R.id.playback);
|
||||
seekBar = findViewById(R.id.progress);
|
||||
loop = findViewById(R.id.loop);
|
||||
textView = findViewById(R.id.text);
|
||||
favorite = findViewById(R.id.favorite);
|
||||
|
||||
appDatabase = AppDatabase.getDatabase(this);
|
||||
favoriteSoundsDao = appDatabase.favoriteSoundsDao();
|
||||
|
||||
// 接收传递的 SoundItem 对象
|
||||
soundItemList = (SoundItem) getIntent().getSerializableExtra("1234");
|
||||
if (soundItemList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
textView.setText(soundItemList.getTitle());
|
||||
|
||||
// 检查数据库中是否存在该音频的收藏记录
|
||||
checkFavoriteStatus();
|
||||
|
||||
//设置收藏点击事件
|
||||
favorite.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
isFavorite = !isFavorite;
|
||||
updateFavoriteIcon();
|
||||
updateDatabase();
|
||||
}
|
||||
});
|
||||
|
||||
// 设置循环图标的点击事件
|
||||
loop.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
isLooping = !isLooping;
|
||||
loop.setImageResource(isLooping ? R.drawable.true_loop : R.drawable.loop);
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.setLooping(isLooping);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 设置播放/暂停图标的点击事件
|
||||
playBack.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
playAudio();
|
||||
}
|
||||
});
|
||||
|
||||
// 获取设备的最大音量值
|
||||
int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
|
||||
// 设置SeekBar的最大值
|
||||
seekBar.setMax(maxVolume);
|
||||
|
||||
// 获取当前音量值
|
||||
int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
|
||||
// 设置SeekBar的初始进度
|
||||
seekBar.setProgress(currentVolume);
|
||||
|
||||
// 设置SeekBar监听器
|
||||
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
// 调整音量
|
||||
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
// 用户开始拖动进度条时执行的操作
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
// 用户停止拖动进度条时执行的操作
|
||||
}
|
||||
});
|
||||
|
||||
// 使用 Glide 加载图片
|
||||
Glide.with(MainApplication.getContext())
|
||||
.asDrawable()
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(soundItemList.getPreUrl())
|
||||
.transform(new CenterCrop())
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
private void checkFavoriteStatus() {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// 检查数据库中是否存在该音频的收藏记录
|
||||
FavoriteSounds favoriteSound = favoriteSoundsDao.getByPath(soundItemList.getMp3Url());
|
||||
isFavorite = favoriteSound != null;
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateFavoriteIcon();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void updateFavoriteIcon() {
|
||||
favorite.setImageResource(isFavorite ? R.drawable.favorite : R.drawable.unfavorite);
|
||||
}
|
||||
|
||||
private void updateDatabase() {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// 判断是否收藏
|
||||
if (isFavorite) {
|
||||
// 插入数据到数据库
|
||||
FavoriteSounds favoriteSound = new FavoriteSounds(
|
||||
soundItemList.getTitle(),
|
||||
soundItemList.getMp3Url(),
|
||||
soundItemList.getPreUrl()
|
||||
);
|
||||
favoriteSoundsDao.insertSound(favoriteSound);
|
||||
} else {
|
||||
// 从数据库删除数据,先根据路径检索出要删除的对象
|
||||
FavoriteSounds favoriteSound = favoriteSoundsDao.getByPath(soundItemList.getMp3Url());
|
||||
if (favoriteSound != null) {
|
||||
favoriteSoundsDao.delete(favoriteSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
private void playAudio() {
|
||||
String audioUrl = soundItemList.getMp3Url(); // 获取音频的URL
|
||||
|
||||
if (mediaPlayer == null) {
|
||||
// 如果MediaPlayer对象为空,则创建一个新的MediaPlayer对象
|
||||
mediaPlayer = new MediaPlayer();
|
||||
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); // 设置音频流类型为音乐
|
||||
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioUrl); // 设置音频数据源
|
||||
mediaPlayer.prepareAsync(); // 异步准备MediaPlayer
|
||||
|
||||
// 设置MediaPlayer准备完成监听器
|
||||
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
mediaPlayer.start(); // 开始播放音频
|
||||
playBack.setImageResource(R.drawable.pause); // 播放时显示暂停图标
|
||||
isPlaying = true; // 设置播放状态为正在播放
|
||||
mediaPlayer.setLooping(isLooping); // 设置是否循环播放
|
||||
}
|
||||
});
|
||||
|
||||
// 设置MediaPlayer错误监听器
|
||||
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
|
||||
@Override
|
||||
public boolean onError(MediaPlayer mp, int what, int extra) {
|
||||
Toast.makeText(PlaySoundActivity.this, "Error playing audio", Toast.LENGTH_SHORT).show(); // 显示错误提示
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 设置MediaPlayer播放完成监听器
|
||||
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
|
||||
@Override
|
||||
public void onCompletion(MediaPlayer mp) {
|
||||
if (!isLooping) {
|
||||
playBack.setImageResource(R.drawable.playback); // 播放完成时显示播放图标
|
||||
isPlaying = false; // 设置播放状态为未播放
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace(); // 打印异常堆栈信息
|
||||
Toast.makeText(PlaySoundActivity.this, "Error setting data source", Toast.LENGTH_SHORT).show(); // 显示错误提示
|
||||
}
|
||||
} else {
|
||||
// 如果MediaPlayer对象已经存在
|
||||
if (isPlaying) {
|
||||
mediaPlayer.pause(); // 暂停播放
|
||||
playBack.setImageResource(R.drawable.playback); // 暂停时显示播放图标
|
||||
} else {
|
||||
mediaPlayer.start(); // 继续播放
|
||||
playBack.setImageResource(R.drawable.pause); // 播放时显示暂停图标
|
||||
}
|
||||
isPlaying = !isPlaying; // 切换播放状态
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,85 +0,0 @@
|
||||
package com.sound.prankparty.FirstFragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.sound.prankparty.JSON.Category;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.SecondFragment.NewRecordActivity;
|
||||
import com.sound.prankparty.Utils.ItemDecoration;
|
||||
import com.sound.prankparty.Utils.JsonParser;
|
||||
import com.sound.prankparty.Utils.LoadJSON;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class SoundFragment extends Fragment {
|
||||
|
||||
ImageView btnBack;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View view = inflater.inflate(R.layout.fragment_sound, container, false);
|
||||
|
||||
RecyclerView recyclerView = view.findViewById(R.id.sound_recyclerview);
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
|
||||
btnBack = view.findViewById(R.id.fragment_sound_setting);
|
||||
|
||||
// 从assets文件夹中读取JSON文件
|
||||
String jsonString = LoadJSON.loadJSONFromAsset("prank.json");
|
||||
//解析读取的String
|
||||
List<Category> categories = JsonParser.parseJson(jsonString);
|
||||
|
||||
recyclerView.setAdapter(new SoundRecyclerViewAdapter(getContext(), categories));
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰。
|
||||
ItemDecoration itemDecoration = new ItemDecoration(16, 19, 10);
|
||||
recyclerView.addItemDecoration(itemDecoration);
|
||||
|
||||
btnBack.setOnClickListener(v -> showCustomBottomSheetDialog());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void showCustomBottomSheetDialog() {
|
||||
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(requireContext());
|
||||
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.setting_dialog, null);
|
||||
//禁止点击其他页面取消
|
||||
bottomSheetDialog.setCanceledOnTouchOutside(false);
|
||||
|
||||
dialogView.findViewById(R.id.privacy).setOnClickListener(v -> {
|
||||
// 处理选项 1
|
||||
Intent intent = new Intent(getActivity(), NewRecordActivity.class);
|
||||
startActivity(intent);
|
||||
//销毁BottomSheetDialog对象
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
dialogView.findViewById(R.id.share).setOnClickListener(v -> {
|
||||
// 处理选项 2
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
dialogView.findViewById(R.id.version).setOnClickListener(v -> {
|
||||
// 处理取消按钮
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
bottomSheetDialog.setContentView(dialogView);
|
||||
bottomSheetDialog.show();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -1,112 +0,0 @@
|
||||
package com.sound.prankparty.FirstFragment;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Typeface;
|
||||
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.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.sound.prankparty.Application.MainApplication;
|
||||
import com.sound.prankparty.JSON.Category;
|
||||
import com.sound.prankparty.R;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SoundRecyclerViewAdapter extends RecyclerView.Adapter<SoundRecyclerViewAdapter.SoundViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private List<Category> categoryList;
|
||||
private final int[] colors;
|
||||
|
||||
public SoundRecyclerViewAdapter(Context context, List<Category> categoryList) {
|
||||
this.context = context;
|
||||
this.categoryList = categoryList;
|
||||
|
||||
colors = new int[]{
|
||||
ContextCompat.getColor(context, R.color.color4),
|
||||
ContextCompat.getColor(context, R.color.color2),
|
||||
ContextCompat.getColor(context, R.color.color3)
|
||||
// 添加更多颜色
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SoundViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sound, parent, false);
|
||||
return new SoundViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull SoundViewHolder holder, int position) {
|
||||
|
||||
Category category = categoryList.get(position);
|
||||
|
||||
// 使用取模运算来循环使用颜色
|
||||
holder.imageView.setBackgroundColor(colors[position % colors.length]);
|
||||
|
||||
String originalName = category.getCategoryName();
|
||||
// 检查名称是否为空,以避免空指针异常
|
||||
if (originalName != null && !originalName.isEmpty()) {
|
||||
// // 将首字母大写
|
||||
// String capitalizedName = originalName.substring(0, 1).toUpperCase() + originalName.substring(1);
|
||||
// 设置文本字体
|
||||
holder.textView.setTypeface(Typeface.createFromAsset(context.getAssets(), "FrancoisOne-Regular.ttf"));
|
||||
//设置文本
|
||||
holder.textView.setText(originalName);
|
||||
} else {
|
||||
// 如果名称为空,可以设置一个默认值或者不设置
|
||||
holder.textView.setText("");
|
||||
}
|
||||
|
||||
if (category != null) {
|
||||
Glide.with(MainApplication.getContext())
|
||||
//指定加载的资源类型为Drawable
|
||||
.asDrawable()
|
||||
//设置跳过内存缓存,即加载的图片不会存储在内存缓存中
|
||||
.skipMemoryCache(true)
|
||||
//设置磁盘缓存策略为DiskCacheStrategy.ALL,即缓存原始图片和转换后的图片
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(category.getCategoryUrl())
|
||||
.transform(new CenterCrop())
|
||||
.into(holder.imageView);
|
||||
|
||||
holder.imageView.setOnClickListener(v -> {
|
||||
Intent intent = new Intent(context, AirHornActivity.class);
|
||||
intent.putExtra("123",category);
|
||||
context.startActivity(intent);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return categoryList.size();
|
||||
}
|
||||
|
||||
static class SoundViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
ImageView imageView;
|
||||
TextView textView;
|
||||
|
||||
public SoundViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.item_imageview_sound);
|
||||
textView = itemView.findViewById(R.id.item_textview_sound);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -139,7 +139,6 @@ public class RadioFragment extends Fragment {
|
||||
}
|
||||
|
||||
// 处理权限请求结果
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
@ -152,7 +151,6 @@ public class RadioFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
// 打开音频选择器
|
||||
|
||||
private void openAudioPicker() {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); // 改为 ACTION_OPEN_DOCUMENT
|
||||
intent.setType("audio/*"); // 设置 MIME 类型为音频
|
||||
@ -161,7 +159,6 @@ public class RadioFragment extends Fragment {
|
||||
}
|
||||
|
||||
// 处理 Activity 结果
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
@ -190,7 +187,7 @@ public class RadioFragment extends Fragment {
|
||||
if (count > 0) {
|
||||
// 在主线程中显示文件已经存在的提示
|
||||
requireActivity().runOnUiThread(() ->
|
||||
Toast.makeText(requireContext(), "该文件已经导入过,不能重复导入", Toast.LENGTH_LONG).show());
|
||||
Toast.makeText(requireContext(), "This file has been imported and cannot be imported again", Toast.LENGTH_LONG).show());
|
||||
} else {
|
||||
// 插入新记录
|
||||
saveSoundsDao.insertSound(new SaveSounds(fileName, audioUri.toString(), lastModifiedDateTime[0], lastModifiedDateTime[1], formatDuration(finalDuration)));
|
||||
@ -199,7 +196,7 @@ public class RadioFragment extends Fragment {
|
||||
e.printStackTrace();
|
||||
// 在主线程中显示错误信息
|
||||
requireActivity().runOnUiThread(() ->
|
||||
Toast.makeText(requireContext(), "插入数据库失败: " + e.getMessage(), Toast.LENGTH_LONG).show());
|
||||
Toast.makeText(requireContext(), "Failed to insert database: " + e.getMessage(), Toast.LENGTH_LONG).show());
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@ -1,106 +0,0 @@
|
||||
package com.sound.prankparty.Main;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.sound.prankparty.R;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private ViewPager2 viewPager2;
|
||||
private TabLayout tabLayout;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
viewPager2 = findViewById(R.id.main_viewpager);
|
||||
tabLayout = findViewById(R.id.main_tablayout);
|
||||
|
||||
MainViewPager2Adapter adapter = new MainViewPager2Adapter(this);
|
||||
viewPager2.setAdapter(adapter);
|
||||
|
||||
// viewPager2.setUserInputEnabled(false); //true:滑动,false:禁止滑动
|
||||
|
||||
new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> {
|
||||
View customView = LayoutInflater.from(this).inflate(R.layout.main_tab_item_custom, null);
|
||||
tab.setCustomView(customView);
|
||||
|
||||
ImageView tabIcon = customView.findViewById(R.id.icon_custom);
|
||||
if (tabIcon != null) {
|
||||
if (position == 0) {
|
||||
tabIcon.setImageResource(R.drawable.main_sound_select);
|
||||
} else if (position == 1) {
|
||||
tabIcon.setImageResource(R.drawable.main_radio_unselect);
|
||||
} else {
|
||||
tabIcon.setImageResource(R.drawable.main_favorite_unselect);
|
||||
}
|
||||
}
|
||||
|
||||
}).attach();
|
||||
|
||||
|
||||
//设置标签选中事件
|
||||
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
View customView = tab.getCustomView();
|
||||
if (customView != null) {
|
||||
ImageView tabIcon = customView.findViewById(R.id.icon_custom);
|
||||
if (tabIcon != null) {
|
||||
if (tab.getPosition() == 0) {
|
||||
tabIcon.setImageResource(R.drawable.main_sound_select);
|
||||
} else if (tab.getPosition() == 1) {
|
||||
tabIcon.setImageResource(R.drawable.main_radio_select);
|
||||
} else {
|
||||
tabIcon.setImageResource(R.drawable.main_favorite_select);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
View customView = tab.getCustomView();
|
||||
if (customView != null) {
|
||||
ImageView tabIcon = customView.findViewById(R.id.icon_custom);
|
||||
if (tabIcon != null) {
|
||||
if (tab.getPosition() == 0) {
|
||||
tabIcon.setImageResource(R.drawable.main_sound_unselect);
|
||||
} else if (tab.getPosition() == 1) {
|
||||
tabIcon.setImageResource(R.drawable.main_radio_unselect);
|
||||
} else {
|
||||
tabIcon.setImageResource(R.drawable.main_favorite_unselect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
// 处理Tab重新选中事件
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//处理返回的flag,返回当前fragment
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
|
||||
// 返回到ViewPager2的当前Fragment
|
||||
viewPager2.setCurrentItem(viewPager2.getCurrentItem());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,40 +0,0 @@
|
||||
package com.sound.prankparty.Main;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
|
||||
import com.sound.prankparty.FirstFragment.SoundFragment;
|
||||
import com.sound.prankparty.SecondFragment.RadioFragment;
|
||||
import com.sound.prankparty.ThirdFragment.FavoriteFragment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MainViewPager2Adapter extends FragmentStateAdapter {
|
||||
|
||||
private List<Fragment> fragmentList;
|
||||
|
||||
public MainViewPager2Adapter(@NonNull FragmentActivity fragmentActivity) {
|
||||
super(fragmentActivity);
|
||||
// 初始化fragmentList并添加Fragment对象
|
||||
fragmentList = new ArrayList<>();
|
||||
fragmentList.add(new SoundFragment());
|
||||
fragmentList.add(new RadioFragment());
|
||||
fragmentList.add(new FavoriteFragment());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
// 根据位置返回相应的Fragment
|
||||
return fragmentList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
// 返回Fragment列表的大小
|
||||
return fragmentList.size();
|
||||
}
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package com.sound;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
public class MainApplication extends Application {
|
||||
/**
|
||||
* 全局的上下文
|
||||
*/
|
||||
private static Context mContext;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
//获取应用的上下文并赋值给 mContext
|
||||
mContext = getApplicationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取context
|
||||
* @return
|
||||
*/
|
||||
public static Context getContext(){
|
||||
return mContext;
|
||||
}
|
||||
|
||||
//重写 onLowMemory 方法,在系统内存不足时调用。这里只是调用了父类的 onLowMemory 方法,没有做其他处理
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,156 +0,0 @@
|
||||
package com.sound.prankparty.SecondFragment;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.MediaRecorder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.sound.prankparty.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class NewRecordActivity extends AppCompatActivity {
|
||||
|
||||
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
|
||||
|
||||
private ImageButton button;
|
||||
private Boolean isStarted = false;
|
||||
private LottieAnimationView animationView;
|
||||
private TextView timeTextView;
|
||||
private Handler handler = new Handler();
|
||||
private long startTime;
|
||||
private MediaRecorder mediaRecorder;
|
||||
private File outputFile;
|
||||
private Runnable updateTimeTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long elapsedTime = currentTime - startTime;
|
||||
timeTextView.setText(formatTime(elapsedTime));
|
||||
handler.postDelayed(this, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_new_record);
|
||||
|
||||
animationView = findViewById(R.id.animation_view);
|
||||
button = findViewById(R.id.new_record_record);
|
||||
timeTextView = findViewById(R.id.new_record_time);
|
||||
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// 检查是否授予了RECORD_AUDIO权限
|
||||
if (ContextCompat.checkSelfPermission(NewRecordActivity.this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||
// 如果未被授予,则请求该权限
|
||||
ActivityCompat.requestPermissions(NewRecordActivity.this, new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_RECORD_AUDIO_PERMISSION);
|
||||
} else {
|
||||
// 如果获得权限,就开始录音
|
||||
toggleRecording();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void toggleRecording() {
|
||||
if (isStarted) {
|
||||
// 停止录音
|
||||
stopRecording();
|
||||
} else {
|
||||
// 开始录音
|
||||
startRecording();
|
||||
}
|
||||
isStarted = !isStarted; // 切换录音状态
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// 获得许可,开始录音
|
||||
toggleRecording();
|
||||
} else {
|
||||
// 权限被拒绝,通知用户
|
||||
Toast.makeText(this, "录音权限被拒绝,请在设置中启用权限", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startRecording() {
|
||||
try {
|
||||
// 初始化MediaRecorder
|
||||
mediaRecorder = new MediaRecorder();
|
||||
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
|
||||
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
|
||||
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
|
||||
|
||||
// 设置输出文件路径
|
||||
String fileName = "recording_" + System.currentTimeMillis() + ".m4a";
|
||||
outputFile = new File(getFilesDir(), fileName);
|
||||
mediaRecorder.setOutputFile(outputFile.getAbsolutePath());
|
||||
|
||||
// 准备并开始录音
|
||||
mediaRecorder.prepare();
|
||||
mediaRecorder.start();
|
||||
|
||||
// 更新UI
|
||||
startTime = System.currentTimeMillis();
|
||||
handler.post(updateTimeTask);
|
||||
animationView.playAnimation();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
// 处理异常
|
||||
}
|
||||
}
|
||||
|
||||
private void stopRecording() {
|
||||
// 停止录音并释放MediaRecorder
|
||||
if (mediaRecorder != null) {
|
||||
mediaRecorder.stop();
|
||||
mediaRecorder.release();
|
||||
mediaRecorder = null;
|
||||
}
|
||||
|
||||
// 更新UI
|
||||
handler.removeCallbacks(updateTimeTask);
|
||||
animationView.cancelAnimation();
|
||||
animationView.setFrame(0);
|
||||
timeTextView.setText("00:00:00");
|
||||
|
||||
Intent intent = new Intent(NewRecordActivity.this, SaveRecordActivity.class);
|
||||
intent.putExtra("audioFilePath", outputFile.getAbsolutePath());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private String formatTime(long elapsedTime) {
|
||||
int seconds = (int) (elapsedTime / 1000) % 60;
|
||||
int minutes = (int) ((elapsedTime / (1000 * 60)) % 60);
|
||||
int hours = (int) ((elapsedTime / (1000 * 60 * 60)) % 24);
|
||||
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
handler.removeCallbacks(updateTimeTask);
|
||||
}
|
||||
}
|
||||
@ -1,326 +0,0 @@
|
||||
package com.sound.prankparty.SecondFragment;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.sound.prankparty.FirstFragment.PlaySoundActivity;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.AppDatabase;
|
||||
import com.sound.prankparty.Room.FavoriteSoundsDao;
|
||||
import com.sound.prankparty.Room.SaveSounds;
|
||||
import com.sound.prankparty.Room.SaveSoundsDao;
|
||||
import com.sound.prankparty.Utils.MyItemTouchHelperCallback;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
public class RadioFragment extends Fragment {
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
private RadioRecyclerViewAdapter radioRecyclerViewAdapter;
|
||||
private ImageView add;
|
||||
private ImageView backgroundTitle;
|
||||
private SaveSoundsDao saveSoundsDao;
|
||||
private MyItemTouchHelperCallback myItemTouchHelperCallback;
|
||||
private ItemTouchHelper itemTouchHelper;
|
||||
private Uri audioUri;
|
||||
private String fileName;
|
||||
private AppDatabase appDatabase;
|
||||
private FavoriteSoundsDao favoriteSoundsDao;
|
||||
private List<SaveSounds> saveSoundsList;
|
||||
private static final int REQUEST_CODE_READ_MEDIA_AUDIO = 1001;
|
||||
private static final int REQUEST_CODE_PICK_AUDIO = 1002;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
// 初始化视图
|
||||
View view = inflater.inflate(R.layout.fragment_radio, container, false);
|
||||
|
||||
// 初始化数据库
|
||||
appDatabase = AppDatabase.getDatabase(requireContext());
|
||||
saveSoundsDao = appDatabase.saveSoundsDao();
|
||||
favoriteSoundsDao = appDatabase.favoriteSoundsDao();
|
||||
|
||||
// 初始化视图组件
|
||||
add = view.findViewById(R.id.fragment_radio_add);
|
||||
backgroundTitle = view.findViewById(R.id.empty_radio_image);
|
||||
recyclerView = view.findViewById(R.id.radio_recyclerview);
|
||||
|
||||
// 设置RecyclerView的布局管理器
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 1));
|
||||
|
||||
// 初始化适配器
|
||||
radioRecyclerViewAdapter = new RadioRecyclerViewAdapter(requireContext(), this, favoriteSoundsDao);
|
||||
recyclerView.setAdapter(radioRecyclerViewAdapter);
|
||||
|
||||
// 初始化 MyItemTouchHelperCallback
|
||||
myItemTouchHelperCallback = new MyItemTouchHelperCallback(this);
|
||||
itemTouchHelper = new ItemTouchHelper(myItemTouchHelperCallback);
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
|
||||
// itemTouchHelper.setSwipeEnabled(false);
|
||||
|
||||
|
||||
// 设置添加按钮的点击事件
|
||||
add.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showCustomBottomSheetDialog();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
recyclerView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
playSound();
|
||||
}
|
||||
});
|
||||
|
||||
// 刷新数据
|
||||
refreshData();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
refreshData();
|
||||
}
|
||||
|
||||
// 显示自定义底部弹窗
|
||||
private void showCustomBottomSheetDialog() {
|
||||
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(requireContext());
|
||||
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_dialog, null);
|
||||
|
||||
bottomSheetDialog.setCanceledOnTouchOutside(false);
|
||||
|
||||
// 设置选项1的点击事件
|
||||
dialogView.findViewById(R.id.option1).setOnClickListener(v -> {
|
||||
// 处理选项 1
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
openAudioPicker();
|
||||
} else {
|
||||
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(requireActivity(),
|
||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_READ_MEDIA_AUDIO);
|
||||
} else {
|
||||
openAudioPicker();
|
||||
}
|
||||
}
|
||||
// 销毁BottomSheetDialog对象
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
// 设置选项2的点击事件
|
||||
dialogView.findViewById(R.id.option2).setOnClickListener(v -> {
|
||||
// 处理选项 2
|
||||
Intent intent = new Intent(getActivity(), NewRecordActivity.class);
|
||||
startActivity(intent);
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
// 设置取消按钮的点击事件
|
||||
dialogView.findViewById(R.id.cancel_button).setOnClickListener(v -> {
|
||||
// 处理取消按钮
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
bottomSheetDialog.setContentView(dialogView);
|
||||
bottomSheetDialog.show();
|
||||
}
|
||||
|
||||
// 处理权限请求结果
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == REQUEST_CODE_READ_MEDIA_AUDIO) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
openAudioPicker();
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "Permission denied", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 打开音频选择器
|
||||
private void openAudioPicker() {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.setType("audio/*");
|
||||
startActivityForResult(intent, REQUEST_CODE_PICK_AUDIO);
|
||||
}
|
||||
|
||||
// 处理Activity结果
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == REQUEST_CODE_PICK_AUDIO && resultCode == RESULT_OK) {
|
||||
if (data != null) {
|
||||
audioUri = data.getData();
|
||||
assert audioUri != null;
|
||||
fileName = getFileName(audioUri);
|
||||
long duration = 0;
|
||||
try {
|
||||
duration = getAudioDuration(audioUri);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
String[] currentDateTime = getCurrentDateTime();
|
||||
|
||||
long finalDuration = duration;
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
saveSoundsDao.insertSound(new SaveSounds(fileName, audioUri.toString(), currentDateTime[0], currentDateTime[1], formatDuration(finalDuration)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// 在主线程中显示错误信息
|
||||
requireActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(requireContext(), "插入数据库失败: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void playSound(){
|
||||
|
||||
// SoundItem soundItem = new SoundItem(audioUri.toString(),"https://resource-sg-public.lux-ad.com/prank/7f35214ab21c8edb7afd193442126aca.png","Baby Sneeze 1");
|
||||
|
||||
String ine = "un";
|
||||
Log.d("dskod",ine);
|
||||
Intent intent = new Intent(requireActivity(), PlaySoundActivity.class);
|
||||
// intent.putExtra("1234", soundItem);
|
||||
requireActivity().startActivity(intent);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 获取文件名
|
||||
private String getFileName(Uri uri) {
|
||||
String result = null;
|
||||
if (Objects.equals(uri.getScheme(), "content")) {
|
||||
try (Cursor cursor = requireActivity().getContentResolver().query(uri, null, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
int displayNameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
|
||||
if (displayNameIndex != -1) {
|
||||
result = cursor.getString(displayNameIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
result = uri.getPath();
|
||||
assert result != null;
|
||||
int cut = result.lastIndexOf('/');
|
||||
if (cut != -1) {
|
||||
result = result.substring(cut + 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 获取音频时长
|
||||
private long getAudioDuration(Uri uri) throws IOException {
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
retriever.setDataSource(requireContext(), uri);
|
||||
String duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||
retriever.release();
|
||||
return duration != null ? Long.parseLong(duration) : 0;
|
||||
}
|
||||
|
||||
// 格式化时长
|
||||
private String formatDuration(long duration) {
|
||||
long minutes = (duration / 1000) / 60;
|
||||
long seconds = (duration / 1000) % 60;
|
||||
return String.format(Locale.getDefault(), "%d:%02d", minutes, seconds);
|
||||
}
|
||||
|
||||
// 获取当前日期和时间
|
||||
public static String[] getCurrentDateTime() {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||
Date now = new Date();
|
||||
String currentDate = dateFormat.format(now);
|
||||
String currentTime = timeFormat.format(now);
|
||||
return new String[]{currentDate, currentTime};
|
||||
}
|
||||
|
||||
// 刷新数据
|
||||
public void refreshData() {
|
||||
new Thread(() -> {
|
||||
saveSoundsList = saveSoundsDao.getAllSounds();
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) add.getLayoutParams();
|
||||
if (saveSoundsList.isEmpty()) {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
backgroundTitle.setVisibility(View.VISIBLE);
|
||||
|
||||
// 清除与底部对齐的约束
|
||||
layoutParams.topToBottom = ConstraintLayout.LayoutParams.UNSET;
|
||||
layoutParams.bottomToTop = ConstraintLayout.LayoutParams.UNSET;
|
||||
|
||||
// 将add移动到屏幕中央
|
||||
layoutParams.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
layoutParams.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
layoutParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
layoutParams.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
} else {
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
backgroundTitle.setVisibility(View.GONE);
|
||||
|
||||
// 清除与中央对齐的约束
|
||||
layoutParams.topToTop = ConstraintLayout.LayoutParams.UNSET;
|
||||
layoutParams.bottomToTop = ConstraintLayout.LayoutParams.UNSET;
|
||||
|
||||
// 将add移动到屏幕底部
|
||||
layoutParams.topToBottom = R.id.radio_recyclerview;
|
||||
layoutParams.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
layoutParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
layoutParams.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
}
|
||||
|
||||
add.setLayoutParams(layoutParams);
|
||||
radioRecyclerViewAdapter.updateData(saveSoundsList);
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
package com.sound.prankparty.SecondFragment;
|
||||
|
||||
import android.content.Context;
|
||||
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.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.FavoriteSounds;
|
||||
import com.sound.prankparty.Room.FavoriteSoundsDao;
|
||||
import com.sound.prankparty.Room.SaveSounds;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class RadioRecyclerViewAdapter extends RecyclerView.Adapter<RadioRecyclerViewAdapter.RadioViewHolder> {
|
||||
|
||||
private List<SaveSounds> saveSoundsList;
|
||||
private Context context;
|
||||
private Fragment fragment;
|
||||
private FavoriteSoundsDao favoriteSoundsDao;
|
||||
|
||||
public RadioRecyclerViewAdapter(Context context, Fragment fragment, FavoriteSoundsDao favoriteSoundsDao) {
|
||||
this.context = context;
|
||||
this.fragment = fragment;
|
||||
this.favoriteSoundsDao = favoriteSoundsDao;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RadioViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_radio, parent, false);
|
||||
return new RadioViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RadioViewHolder holder, int position) {
|
||||
SaveSounds saveSound = saveSoundsList.get(position);
|
||||
holder.title.setText(saveSound.getName());
|
||||
holder.date.setText(saveSound.getDate());
|
||||
holder.time.setText(saveSound.getTime());
|
||||
holder.duration.setText(saveSound.getDuration());
|
||||
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
final boolean[] isFavorite = {checkFavoriteStatus(saveSound)};
|
||||
// 更新 UI 需要在主线程中执行
|
||||
fragment.requireActivity().runOnUiThread(() -> {
|
||||
updateFavoriteIcon(holder, isFavorite[0]);
|
||||
holder.favorite.setOnClickListener(v -> {
|
||||
isFavorite[0] = !isFavorite[0];
|
||||
updateFavoriteIcon(holder, isFavorite[0]);
|
||||
updateDatabase(saveSound, isFavorite[0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return saveSoundsList != null ? saveSoundsList.size() : 0;
|
||||
}
|
||||
|
||||
public void updateData(List<SaveSounds> newSaveSoundsList) {
|
||||
this.saveSoundsList = newSaveSoundsList;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private boolean checkFavoriteStatus(SaveSounds saveSound) {
|
||||
FavoriteSounds favoriteSound = favoriteSoundsDao.getByPath(saveSound.getPath());
|
||||
return favoriteSound != null;
|
||||
}
|
||||
|
||||
private void updateDatabase(SaveSounds saveSound, boolean isFavorite) {
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
if (isFavorite) {
|
||||
favoriteSoundsDao.insertSound(new FavoriteSounds(saveSound.getName(), saveSound.getPath(), ""));
|
||||
} else {
|
||||
favoriteSoundsDao.delete(favoriteSoundsDao.getByPath(saveSound.getPath()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateFavoriteIcon(RadioViewHolder holder, boolean isFavorite) {
|
||||
holder.favorite.setImageResource(isFavorite ? R.drawable.favorite : R.drawable.unfavorite);
|
||||
}
|
||||
|
||||
static class RadioViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
TextView title;
|
||||
TextView date;
|
||||
TextView time;
|
||||
TextView duration;
|
||||
ImageView favorite;
|
||||
|
||||
public RadioViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
title = itemView.findViewById(R.id.title);
|
||||
date = itemView.findViewById(R.id.date);
|
||||
time = itemView.findViewById(R.id.time);
|
||||
duration = itemView.findViewById(R.id.duration);
|
||||
favorite = itemView.findViewById(R.id.favorite);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,218 +0,0 @@
|
||||
package com.sound.prankparty.SecondFragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.sound.prankparty.Main.MainActivity;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.AppDatabase;
|
||||
import com.sound.prankparty.Room.SaveSounds;
|
||||
import com.sound.prankparty.Room.SaveSoundsDao;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class SaveRecordActivity extends AppCompatActivity {
|
||||
|
||||
private String audioFilePath;
|
||||
private String inputText;
|
||||
private MediaPlayer mediaPlayer;
|
||||
private TextView durationTextView;
|
||||
private String datePart;
|
||||
private String timePart;
|
||||
private ImageView playButton;
|
||||
private EditText editText;
|
||||
private Button saveButton;
|
||||
private boolean isPlaying = false;
|
||||
private AppDatabase appDatabase;
|
||||
private SaveSoundsDao saveSoundsDao;
|
||||
private int duration;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_save_record);
|
||||
|
||||
// 获取传递过来的录音文件路径
|
||||
audioFilePath = getIntent().getStringExtra("audioFilePath");
|
||||
if (audioFilePath == null) {
|
||||
Toast.makeText(this, "音频文件路径无效", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Log.d("SaveRecordActivity", audioFilePath);
|
||||
|
||||
playButton = findViewById(R.id.save_record_play);
|
||||
durationTextView = findViewById(R.id.save_record_time);
|
||||
editText = findViewById(R.id.save_record_name);
|
||||
saveButton = findViewById(R.id.save_record_save);
|
||||
|
||||
// 初始化数据库和 DAO
|
||||
appDatabase = AppDatabase.getDatabase(this); // 获取数据库实例
|
||||
saveSoundsDao = appDatabase.saveSoundsDao();
|
||||
|
||||
// 设置焦点变化监听器
|
||||
editText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
editText.setCursorVisible(hasFocus);
|
||||
}
|
||||
});
|
||||
|
||||
// 处理全局点击事件
|
||||
findViewById(R.id.main).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v instanceof ViewGroup) {
|
||||
clearFocusFromAllChildren((ViewGroup) v);
|
||||
} else {
|
||||
clearFocus();
|
||||
}
|
||||
// 获取输入文本
|
||||
inputText = editText.getText().toString();
|
||||
Log.d("lux231", "13" + inputText);
|
||||
}
|
||||
});
|
||||
|
||||
// 显示音频文件的时长
|
||||
displayAudioDuration();
|
||||
|
||||
playButton.setOnClickListener(v -> playOrPauseAudio());
|
||||
|
||||
saveButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
inputText = editText.getText().toString();
|
||||
if (inputText == null || inputText.trim().isEmpty()) {
|
||||
Toast.makeText(getApplicationContext(), "名称不能为空", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
formatDateTime();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
saveSoundsDao.insertSound(new SaveSounds(inputText, audioFilePath, datePart, timePart, formatTime(duration)));
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
//FLAG_ACTIVITY_CLEAR_TOP标志来清除栈中的Activity,传递Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
Intent intent = new Intent(SaveRecordActivity.this, MainActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void clearFocusFromAllChildren(ViewGroup parent) {
|
||||
for (int i = 0; i < parent.getChildCount(); i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
if (child instanceof ViewGroup) {
|
||||
clearFocusFromAllChildren((ViewGroup) child);
|
||||
} else {
|
||||
child.clearFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearFocus() {
|
||||
editText.clearFocus();
|
||||
}
|
||||
|
||||
private void displayAudioDuration() {
|
||||
if (audioFilePath != null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioFilePath);
|
||||
mediaPlayer.prepare();
|
||||
|
||||
// 获取音频文件的时长
|
||||
duration = mediaPlayer.getDuration();
|
||||
durationTextView.setText(formatTime(duration));
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "无法加载音频", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, "音频文件路径无效", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void playOrPauseAudio() {
|
||||
if (isPlaying) {
|
||||
mediaPlayer.pause();
|
||||
playButton.setImageResource(R.drawable.playback); // 更新按钮为播放图标
|
||||
isPlaying = false;
|
||||
} else {
|
||||
if (mediaPlayer == null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioFilePath);
|
||||
mediaPlayer.prepare();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "无法播放音频", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
mediaPlayer.start();
|
||||
playButton.setImageResource(R.drawable.pause); // 更新按钮为暂停图标
|
||||
isPlaying = true;
|
||||
|
||||
mediaPlayer.setOnCompletionListener(mp -> {
|
||||
Toast.makeText(this, "播放完成", Toast.LENGTH_SHORT).show();
|
||||
playButton.setImageResource(R.drawable.playback); // 恢复播放图标
|
||||
isPlaying = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mediaPlayer != null) {
|
||||
if (isPlaying) {
|
||||
mediaPlayer.stop();
|
||||
}
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
private String formatTime(int duration) {
|
||||
int seconds = (duration / 1000) % 60;
|
||||
int minutes = (duration / (1000 * 60)) % 60;
|
||||
int hours = (duration / (1000 * 60 * 60)) % 24;
|
||||
return String.format("%02d:%02d:%02d", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
private void formatDateTime() {
|
||||
Date currentDate = new Date();
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
|
||||
datePart = dateFormat.format(currentDate);
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||
timePart = timeFormat.format(currentDate);
|
||||
}
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
package com.sound.prankparty.StartUp;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.widget.ProgressBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.sound.prankparty.Main.MainActivity;
|
||||
import com.sound.prankparty.R;
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
|
||||
private static final int SPLASH_TIME_OUT = 5000;
|
||||
private ProgressBar progressBar;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_splash);
|
||||
|
||||
// ImageView imageView = findViewById(R.id.splash_image);
|
||||
// Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.startup_background);
|
||||
// int targetWidth = imageView.getWidth();
|
||||
// int targetHeight = imageView.getHeight();
|
||||
// Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, targetWidth, targetHeight, true);
|
||||
// imageView.setImageBitmap(scaledBitmap);
|
||||
|
||||
|
||||
progressBar = findViewById(R.id.progressBar);
|
||||
|
||||
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}, SPLASH_TIME_OUT);
|
||||
|
||||
// 进度条进展
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i <= 100; i++) {
|
||||
final int progress = i;
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
progressBar.setProgress(progress);
|
||||
}
|
||||
});
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
package com.sound.prankparty.ThirdFragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.AppDatabase;
|
||||
import com.sound.prankparty.Room.FavoriteSounds;
|
||||
import com.sound.prankparty.Room.FavoriteSoundsDao;
|
||||
import com.sound.prankparty.Utils.FavoriteSoundsViewModel;
|
||||
import com.sound.prankparty.Utils.ItemDecoration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class FavoriteFragment extends Fragment {
|
||||
|
||||
private AppDatabase appDatabase;
|
||||
private FavoriteSoundsDao favoriteSoundsDao;
|
||||
private List<FavoriteSounds> favoriteSoundsList;
|
||||
private RecyclerView recyclerView;
|
||||
private FavoriteRecyclerViewAdapter favoriteRecyclerViewAdapter;
|
||||
private ImageView tips;
|
||||
private ImageView image;
|
||||
private FavoriteSoundsViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_favorite, container, false);
|
||||
|
||||
// 使用 ApplicationContext 来获取 ViewModel
|
||||
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getActivity().getApplication())).get(FavoriteSoundsViewModel.class);
|
||||
|
||||
recyclerView = view.findViewById(R.id.favorite_recyclerview);
|
||||
tips = view.findViewById(R.id.fragment_favorite_tips);
|
||||
image = view.findViewById(R.id.fragment_favorite_image);
|
||||
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
|
||||
|
||||
favoriteRecyclerViewAdapter = new FavoriteRecyclerViewAdapter(requireContext(), this);
|
||||
recyclerView.setAdapter(favoriteRecyclerViewAdapter);
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰。
|
||||
ItemDecoration itemDecoration = new ItemDecoration(16, 19, 10);
|
||||
recyclerView.addItemDecoration(itemDecoration);
|
||||
|
||||
appDatabase = AppDatabase.getDatabase(requireContext());
|
||||
favoriteSoundsDao = appDatabase.favoriteSoundsDao();
|
||||
|
||||
// 观察 LiveData 的变化
|
||||
viewModel.getFavoriteSoundsLiveData().observe(getViewLifecycleOwner(), favoriteSoundsList -> {
|
||||
if (favoriteSoundsList == null || favoriteSoundsList.isEmpty()) {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
tips.setVisibility(View.VISIBLE);
|
||||
image.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
tips.setVisibility(View.GONE);
|
||||
image.setVisibility(View.GONE);
|
||||
}
|
||||
favoriteRecyclerViewAdapter.updateData(favoriteSoundsList);
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// 触发数据刷新
|
||||
viewModel.refreshData();
|
||||
}
|
||||
}
|
||||
@ -1,81 +0,0 @@
|
||||
package com.sound.prankparty.ThirdFragment;
|
||||
|
||||
import android.content.Context;
|
||||
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.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.sound.prankparty.Application.MainApplication;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.FavoriteSounds;
|
||||
import com.sound.prankparty.Utils.FavoriteSoundsDiffCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FavoriteRecyclerViewAdapter extends RecyclerView.Adapter<FavoriteRecyclerViewAdapter.FavoriteRecyclerViewHolder> {
|
||||
|
||||
private List<FavoriteSounds> favoriteSoundsList = new ArrayList<>();
|
||||
private Context context;
|
||||
private Fragment fragment;
|
||||
|
||||
public FavoriteRecyclerViewAdapter(Context context, Fragment fragment) {
|
||||
this.context = context;
|
||||
this.fragment = fragment;
|
||||
}
|
||||
|
||||
public void updateData(List<FavoriteSounds> newFavoriteSoundsList) {
|
||||
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new FavoriteSoundsDiffCallback(favoriteSoundsList, newFavoriteSoundsList));
|
||||
favoriteSoundsList.clear();
|
||||
favoriteSoundsList.addAll(newFavoriteSoundsList);
|
||||
diffResult.dispatchUpdatesTo(this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public FavoriteRecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_favorite, parent, false);
|
||||
return new FavoriteRecyclerViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull FavoriteRecyclerViewHolder holder, int position) {
|
||||
FavoriteSounds favoriteSounds = favoriteSoundsList.get(position);
|
||||
holder.textView.setText(favoriteSounds.getName());
|
||||
|
||||
Glide.with(MainApplication.getContext())
|
||||
.asDrawable()
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(favoriteSounds.getImagePath())
|
||||
.transform(new CenterCrop())
|
||||
.into(holder.imageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return favoriteSoundsList != null ? favoriteSoundsList.size() : 0;
|
||||
}
|
||||
|
||||
static class FavoriteRecyclerViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView imageView;
|
||||
TextView textView;
|
||||
|
||||
public FavoriteRecyclerViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.item_imageview_favorite);
|
||||
textView = itemView.findViewById(R.id.item_imageview_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,20 +8,23 @@
|
||||
android:id="@+id/splash_image"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:src="@mipmap/start_up"
|
||||
android:scaleType="fitXY"/>
|
||||
android:scaleType="fitXY"
|
||||
android:src="@mipmap/start_up" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="6dp"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginBottom="128dp"
|
||||
android:max="100"
|
||||
android:progress="0"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:progressDrawable="@drawable/seek_bar_color"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintVertical_bias="0.5" />
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user