V1.0.0(4)优化

This commit is contained in:
lihongwei 2024-09-25 16:24:09 +08:00
parent 4831c39881
commit c0f62a21f1
23 changed files with 78 additions and 1889 deletions

View File

@ -11,7 +11,7 @@ android {
}
defaultConfig {
applicationId = "com.sound.prankparty.test"
applicationId = "com.sound.prankparty"
minSdk = 23
targetSdk = 34
versionCode = 1

View File

@ -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" />

View File

@ -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();
}
}
}

View File

@ -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")

View File

@ -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);
});
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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());
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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>