V1.0.0(2),优化
This commit is contained in:
parent
76b26d0126
commit
c660170265
@ -6,6 +6,10 @@ android {
|
||||
namespace = "com.sound.prankparty"
|
||||
compileSdk = 34
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.sound.prankparty.test"
|
||||
minSdk = 23
|
||||
|
||||
@ -4,14 +4,16 @@
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
|
||||
<application
|
||||
android:name=".Application.MainApplication"
|
||||
android:name="com.sound.MainApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
@ -22,23 +24,26 @@
|
||||
android:theme="@style/Theme.PrankPartyDemo"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".SecondFragment.SaveRecordActivity"
|
||||
android:name=".Activity.PrivacyActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".SecondFragment.NewRecordActivity"
|
||||
android:name=".Activity.SaveRecordActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".FirstFragment.PlaySoundActivity"
|
||||
android:name=".Activity.NewRecordActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".FirstFragment.AirHornActivity"
|
||||
android:name=".Activity.PlaySoundActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".StartUp.SplashActivity"
|
||||
android:name=".Activity.AirHornActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".Activity.SplashActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.StartUp" />
|
||||
<activity
|
||||
android:name=".Main.MainActivity"
|
||||
android:name=".Activity.MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
86
app/src/main/assets/privacy.html
Normal file
86
app/src/main/assets/privacy.html
Normal file
@ -0,0 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Privacy Policy</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
h1, h2 {
|
||||
color: #333;
|
||||
}
|
||||
h2 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
p {
|
||||
margin: 10px 0;
|
||||
}
|
||||
ul {
|
||||
margin: 10px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Privacy Policy</h1>
|
||||
<p><strong>Date:</strong> August 9, 2024</p>
|
||||
|
||||
<p>We provide this Privacy Policy to help you understand how we collect, use, and disclose information, including what you may provide to us or that we obtain from our products and services. We treat your privacy very seriously. Your privacy is important to us.</p>
|
||||
|
||||
<h2>Information Collection and Use</h2>
|
||||
<p>For a better experience, while using our Service, we may require you to provide us with certain personally identifiable information, such as users' name, address, location, pictures, etc. The information that we request will be retained on your device and is not collected or retained by us in any way and used as described in this privacy policy.</p>
|
||||
<p>The app does use third-party services that may collect information used to identify you.</p>
|
||||
<p>Please refer to the privacy policy of the third-party service provider used by the application:</p>
|
||||
<ul>
|
||||
<li>Google Play Services</li>
|
||||
<li>Google Analytics for Firebase</li>
|
||||
<li>Firebase Crashlytics</li>
|
||||
<li>Unity</li>
|
||||
<li>AppLovin</li>
|
||||
<li>Pangle</li>
|
||||
<li>Mintegral</li>
|
||||
<li>Bigo</li>
|
||||
<li>Ironsource</li>
|
||||
<li>Vungle</li>
|
||||
</ul>
|
||||
|
||||
<h2>Log Data</h2>
|
||||
<p>We want to inform you that whenever you use our Service, in case of an error in the app, we collect data and information (through third-party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing our Service, the time and date of your use of the Service, and other statistics.</p>
|
||||
|
||||
<h2>Cookies</h2>
|
||||
<p>Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.</p>
|
||||
<p>This Service does not use these “cookies” explicitly. However, the app may use third-party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this Service.</p>
|
||||
|
||||
<h2>Service Providers</h2>
|
||||
<p>We may employ third-party companies and individuals due to the following reasons:</p>
|
||||
<ul>
|
||||
<li>To facilitate our Service</li>
|
||||
<li>To provide the Service on our behalf</li>
|
||||
<li>To perform Service-related services</li>
|
||||
<li>To assist us in analyzing how our Service is used</li>
|
||||
</ul>
|
||||
<p>We want to inform users of this Service that these third parties have access to their Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.</p>
|
||||
|
||||
<h2>Security</h2>
|
||||
<p>We value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and we cannot guarantee its absolute security.</p>
|
||||
|
||||
<h2>Links to Other Sites</h2>
|
||||
<p>This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by us. Therefore, we strongly advise you to review the Privacy Policy of these websites. We have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.</p>
|
||||
|
||||
<h2>Children’s Privacy</h2>
|
||||
<p>These Services do not address anyone under the age of 13. We do not knowingly collect personally identifiable information from children under 13 years of age. In the case we discover that a child under 13 has provided us with personal information, we will immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact us so that we will be able to take the necessary actions.</p>
|
||||
|
||||
<h2>Changes to This Privacy Policy</h2>
|
||||
<p>We may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. We will notify you of any changes by posting the new Privacy Policy on this page.</p>
|
||||
|
||||
<h2>Privacy Questions</h2>
|
||||
<p>We may update the Privacy Policy from time to time. When we change the policy in a material way, a notice will be posted on our website along with the updated Privacy Policy.</p>
|
||||
<p>If you have any questions or concerns about our Privacy Policy or data processing, please contact us: <a href="elizavetasalutina@gmail.com">elizavetasalutina@gmail.com</a>.</p>
|
||||
</body>
|
||||
</html>
|
||||
33
app/src/main/java/com/sound/MainApplication.java
Normal file
33
app/src/main/java/com/sound/MainApplication.java
Normal file
@ -0,0 +1,33 @@
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.sound.prankparty.Activity;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.sound.prankparty.Adapter.AirHornRecyclerViewAdapter;
|
||||
import com.sound.prankparty.JSON.Category;
|
||||
import com.sound.prankparty.JSON.SoundItem;
|
||||
import com.sound.prankparty.Utils.ItemDecoration;
|
||||
import com.sound.prankparty.databinding.ActivityAirhonrBinding;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AirHornActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityAirhonrBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityAirhonrBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
binding.airHornRecyclerview.setLayoutManager(new GridLayoutManager(this, 3));
|
||||
|
||||
// 接收传递的 List<Category> 对象
|
||||
Category categories = (Category) getIntent().getSerializableExtra("123");
|
||||
// 获取颜色值
|
||||
int receivedColor = getIntent().getIntExtra("color", Color.TRANSPARENT); // 默认值为透明色
|
||||
|
||||
if (categories == null) {
|
||||
// 处理 categories 为 null 的情况
|
||||
return;
|
||||
}
|
||||
List<SoundItem> soundItemList = categories.getSoundItemList();
|
||||
String categoryName = categories.getCategoryName();
|
||||
|
||||
binding.airHornRecyclerview.setAdapter(new AirHornRecyclerViewAdapter(this, soundItemList,receivedColor));
|
||||
|
||||
binding.airHornTitle.setText(categoryName);
|
||||
binding.airHornBack.setOnClickListener(v -> finish());
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰。
|
||||
ItemDecoration itemDecoration = new ItemDecoration(16, 19, 10);
|
||||
binding.airHornRecyclerview.addItemDecoration(itemDecoration);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package com.sound.prankparty.Activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import com.sound.prankparty.Adapter.MainViewPager2Adapter;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.databinding.ActivityMainBinding;
|
||||
import com.sound.prankparty.databinding.MainTabItemCustomBinding;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityMainBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
MainViewPager2Adapter adapter = new MainViewPager2Adapter(this);
|
||||
binding.mainViewpager.setAdapter(adapter);
|
||||
|
||||
new TabLayoutMediator(binding.mainTablayout, binding.mainViewpager, (tab, position) -> {
|
||||
MainTabItemCustomBinding tabBinding = MainTabItemCustomBinding.inflate(LayoutInflater.from(this));
|
||||
tab.setCustomView(tabBinding.getRoot());
|
||||
|
||||
if (position == 0) {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_sound_select);
|
||||
} else if (position == 1) {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_radio_unselect);
|
||||
} else {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_favorite_unselect);
|
||||
}
|
||||
}).attach();
|
||||
|
||||
//设置标签选中事件
|
||||
binding.mainTablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
if (tab.getCustomView() != null) {
|
||||
MainTabItemCustomBinding tabBinding = MainTabItemCustomBinding.bind(tab.getCustomView());
|
||||
if (tab.getPosition() == 0) {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_sound_select);
|
||||
} else if (tab.getPosition() == 1) {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_radio_select);
|
||||
} else {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_favorite_select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
if (tab.getCustomView() != null) {
|
||||
MainTabItemCustomBinding tabBinding = MainTabItemCustomBinding.bind(tab.getCustomView());
|
||||
if (tab.getPosition() == 0) {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_sound_unselect);
|
||||
} else if (tab.getPosition() == 1) {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_radio_unselect);
|
||||
} else {
|
||||
tabBinding.iconCustom.setImageResource(R.drawable.main_favorite_unselect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(TabLayout.Tab tab) {
|
||||
// 处理Tab重新选中事件
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
|
||||
// 返回到ViewPager2的当前Fragment
|
||||
binding.mainViewpager.setCurrentItem(binding.mainViewpager.getCurrentItem());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,145 @@
|
||||
package com.sound.prankparty.Activity;
|
||||
|
||||
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.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.sound.prankparty.databinding.ActivityNewRecordBinding;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class NewRecordActivity extends AppCompatActivity {
|
||||
|
||||
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
|
||||
|
||||
private ActivityNewRecordBinding binding;
|
||||
private Boolean isStarted = false;
|
||||
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;
|
||||
binding.newRecordTime.setText(formatTime(elapsedTime));
|
||||
handler.postDelayed(this, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityNewRecordBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
binding.newRecordRecord.setOnClickListener(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();
|
||||
}
|
||||
});
|
||||
|
||||
binding.newRecordBack.setOnClickListener(v -> finish());
|
||||
}
|
||||
|
||||
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);
|
||||
binding.animationView.playAnimation();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
// 处理异常
|
||||
}
|
||||
}
|
||||
|
||||
private void stopRecording() {
|
||||
// 停止录音并释放MediaRecorder
|
||||
if (mediaRecorder != null) {
|
||||
mediaRecorder.stop();
|
||||
mediaRecorder.release();
|
||||
mediaRecorder = null;
|
||||
}
|
||||
|
||||
// 更新UI
|
||||
handler.removeCallbacks(updateTimeTask);
|
||||
binding.animationView.cancelAnimation();
|
||||
binding.animationView.setFrame(0);
|
||||
binding.newRecordTime.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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,286 @@
|
||||
package com.sound.prankparty.Activity;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.SeekBar;
|
||||
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.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 com.sound.prankparty.databinding.ActivityPlaySoundBinding;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class PlaySoundActivity extends AppCompatActivity {
|
||||
|
||||
private MediaPlayer mediaPlayer;
|
||||
private SoundItem soundItemList;
|
||||
private AudioManager audioManager;
|
||||
private boolean isPlaying = false; // 默认未播放
|
||||
private boolean isLooping = false; // 默认不循环
|
||||
private AppDatabase appDatabase;
|
||||
private FavoriteSoundsDao favoriteSoundsDao;
|
||||
private boolean isFavorite = false; // 默认不收藏
|
||||
|
||||
private ActivityPlaySoundBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityPlaySoundBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// 获取音频管理器
|
||||
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
|
||||
|
||||
appDatabase = AppDatabase.getDatabase(this);
|
||||
favoriteSoundsDao = appDatabase.favoriteSoundsDao();
|
||||
|
||||
// 接收传递的 SoundItem 对象
|
||||
soundItemList = (SoundItem) getIntent().getSerializableExtra("1234");
|
||||
if (soundItemList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d("qweeq", soundItemList.getMp3Url());
|
||||
|
||||
binding.text.setText(soundItemList.getTitle());
|
||||
binding.back.setOnClickListener(v -> finish());
|
||||
|
||||
// 检查数据库中是否存在该音频的收藏记录
|
||||
checkFavoriteStatus();
|
||||
|
||||
// 设置收藏点击事件
|
||||
binding.favorite.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
isFavorite = !isFavorite;
|
||||
updateFavoriteIcon();
|
||||
updateDatabase();
|
||||
}
|
||||
});
|
||||
|
||||
// 设置循环图标的点击事件
|
||||
binding.loop.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
isLooping = !isLooping;
|
||||
binding.loop.setImageResource(isLooping ? R.drawable.true_loop : R.drawable.loop);
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.setLooping(isLooping);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 设置播放/暂停图标的点击事件
|
||||
binding.playback.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
playAudio();
|
||||
}
|
||||
});
|
||||
|
||||
// 获取设备的最大音量值
|
||||
int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
|
||||
// 设置SeekBar的最大值
|
||||
binding.progress.setMax(maxVolume);
|
||||
|
||||
// 获取当前音量值
|
||||
int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
|
||||
// 设置SeekBar的初始进度
|
||||
binding.progress.setProgress(currentVolume);
|
||||
|
||||
// 设置SeekBar监听器
|
||||
binding.progress.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) {
|
||||
// 用户停止拖动进度条时执行的操作
|
||||
}
|
||||
});
|
||||
|
||||
// 注册广播接收器
|
||||
IntentFilter filter = new IntentFilter("android.media.VOLUME_CHANGED_ACTION");
|
||||
registerReceiver(volumeReceiver, filter);
|
||||
|
||||
// 使用 Glide 加载图片
|
||||
Glide.with(MainApplication.getContext())
|
||||
.asDrawable()
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(soundItemList.getPreUrl())
|
||||
.placeholder(R.mipmap.default_image)
|
||||
.error(R.mipmap.default_image)
|
||||
.transform(new CenterCrop())
|
||||
.into(binding.image);
|
||||
}
|
||||
|
||||
|
||||
private BroadcastReceiver volumeReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")) {
|
||||
// 获取当前音量值并更新SeekBar的进度
|
||||
int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
|
||||
binding.progress.setProgress(currentVolume);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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() {
|
||||
binding.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 {
|
||||
if (audioUrl.startsWith("content://")) {
|
||||
// 如果音频URL是content://格式,使用URI方式设置数据源
|
||||
Uri audioUri = Uri.parse(audioUrl);
|
||||
mediaPlayer.setDataSource(this, audioUri);
|
||||
} else {
|
||||
// 普通URL格式,使用字符串方式设置数据源
|
||||
mediaPlayer.setDataSource(audioUrl);
|
||||
}
|
||||
|
||||
mediaPlayer.prepareAsync(); // 异步准备MediaPlayer
|
||||
|
||||
// 设置MediaPlayer准备完成监听器
|
||||
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
|
||||
@Override
|
||||
public void onPrepared(MediaPlayer mp) {
|
||||
mediaPlayer.start(); // 开始播放音频
|
||||
binding.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) {
|
||||
binding.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(); // 暂停播放
|
||||
binding.playback.setImageResource(R.drawable.playback); // 暂停时显示播放图标
|
||||
} else {
|
||||
mediaPlayer.start(); // 继续播放
|
||||
binding.playback.setImageResource(R.drawable.pause); // 播放时显示暂停图标
|
||||
}
|
||||
isPlaying = !isPlaying; // 切换播放状态
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
// 注销广播接收器
|
||||
unregisterReceiver(volumeReceiver);
|
||||
|
||||
if (mediaPlayer != null) {
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.sound.prankparty.Activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.sound.prankparty.R;
|
||||
|
||||
public class PrivacyActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_privacy);
|
||||
|
||||
WebView webView = findViewById(R.id.webview);
|
||||
ImageView back = findViewById(R.id.btn_back);
|
||||
// 设置WebView的客户端
|
||||
webView.setWebViewClient(new WebViewClient());
|
||||
|
||||
back.setOnClickListener(v -> finish());
|
||||
|
||||
webView.loadUrl("file:///android_asset/privacy.html");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,207 @@
|
||||
package com.sound.prankparty.Activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.AppDatabase;
|
||||
import com.sound.prankparty.Room.SaveSounds;
|
||||
import com.sound.prankparty.Room.SaveSoundsDao;
|
||||
import com.sound.prankparty.databinding.ActivitySaveRecordBinding;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
public class SaveRecordActivity extends AppCompatActivity {
|
||||
|
||||
private ActivitySaveRecordBinding binding;
|
||||
private String audioFilePath;
|
||||
private String inputText;
|
||||
private MediaPlayer mediaPlayer;
|
||||
private String datePart;
|
||||
private String timePart;
|
||||
private boolean isPlaying = false;
|
||||
private AppDatabase appDatabase;
|
||||
private SaveSoundsDao saveSoundsDao;
|
||||
private int duration;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivitySaveRecordBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// 获取传递过来的录音文件路径
|
||||
audioFilePath = getIntent().getStringExtra("audioFilePath");
|
||||
if (audioFilePath == null) {
|
||||
Toast.makeText(this, "音频文件路径无效", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
Log.d("SaveRecordActivity", audioFilePath);
|
||||
|
||||
// 初始化数据库和 DAO
|
||||
appDatabase = AppDatabase.getDatabase(this);
|
||||
saveSoundsDao = appDatabase.saveSoundsDao();
|
||||
|
||||
|
||||
// 创建一个 SpannableString 并设置它的大小
|
||||
SpannableString hint = new SpannableString(getString(R.string.give_name));
|
||||
hint.setSpan(new AbsoluteSizeSpan(15, true), 0, hint.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // 设置字体大小为 20sp
|
||||
|
||||
binding.saveRecordName.setHint(hint);
|
||||
|
||||
// 设置焦点变化监听器
|
||||
binding.saveRecordName.setOnFocusChangeListener((v, hasFocus) -> binding.saveRecordName.setCursorVisible(hasFocus));
|
||||
|
||||
binding.saveRecordBack.setOnClickListener(v -> finish());
|
||||
|
||||
// 处理全局点击事件
|
||||
binding.main.setOnClickListener(v -> {
|
||||
if (v instanceof ViewGroup) {
|
||||
clearFocusFromAllChildren((ViewGroup) v);
|
||||
} else {
|
||||
clearFocus();
|
||||
}
|
||||
inputText = binding.saveRecordName.getText().toString();
|
||||
Log.d("lux231", "13" + inputText);
|
||||
});
|
||||
|
||||
// 显示音频文件的时长
|
||||
displayAudioDuration();
|
||||
|
||||
binding.saveRecordPlay.setOnClickListener(v -> playOrPauseAudio());
|
||||
|
||||
binding.saveRecordSave.setOnClickListener(v -> {
|
||||
inputText = binding.saveRecordName.getText().toString();
|
||||
if (inputText == null || inputText.trim().isEmpty()) {
|
||||
Toast.makeText(getApplicationContext(), "名称不能为空", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
formatDateTime();
|
||||
|
||||
new Thread(() -> {
|
||||
saveSoundsDao.insertSound(new SaveSounds(inputText, audioFilePath, datePart, timePart, formatTime(duration)));
|
||||
|
||||
runOnUiThread(() -> {
|
||||
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() {
|
||||
binding.saveRecordName.clearFocus();
|
||||
}
|
||||
|
||||
private void displayAudioDuration() {
|
||||
if (audioFilePath != null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioFilePath);
|
||||
mediaPlayer.prepare();
|
||||
|
||||
duration = mediaPlayer.getDuration();
|
||||
binding.saveRecordTime.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();
|
||||
binding.saveRecordPlay.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();
|
||||
binding.saveRecordPlay.setImageResource(R.drawable.pause); // 更新按钮为暂停图标
|
||||
isPlaying = true;
|
||||
|
||||
mediaPlayer.setOnCompletionListener(mp -> {
|
||||
Toast.makeText(this, "播放完成", Toast.LENGTH_SHORT).show();
|
||||
binding.saveRecordPlay.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();
|
||||
|
||||
// 自定义DateFormatSymbols以使用小写的am和pm
|
||||
DateFormatSymbols dfs = new DateFormatSymbols(Locale.ENGLISH);
|
||||
dfs.setAmPmStrings(new String[]{"am", "pm"});
|
||||
// 新的格式
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH);
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mma", Locale.ENGLISH);
|
||||
timeFormat.setDateFormatSymbols(dfs);
|
||||
|
||||
// 赋值给原有变量名
|
||||
datePart = dateFormat.format(currentDate);
|
||||
timePart = timeFormat.format(currentDate);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package com.sound.prankparty.Activity;
|
||||
|
||||
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.databinding.ActivitySplashBinding;
|
||||
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
|
||||
private static final int SPLASH_TIME_OUT = 5000;
|
||||
private ActivitySplashBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivitySplashBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
// 使用 ViewBinding 引用 progressBar
|
||||
ProgressBar progressBar = binding.progressBar;
|
||||
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
Intent intent = new Intent(SplashActivity.this, MainActivity.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}, SPLASH_TIME_OUT);
|
||||
|
||||
// 进度条进展
|
||||
new Thread(() -> {
|
||||
for (int i = 0; i <= 100; i++) {
|
||||
final int progress = i;
|
||||
runOnUiThread(() -> progressBar.setProgress(progress));
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package com.sound.prankparty.Adapter;
|
||||
|
||||
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.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.sound.MainApplication;
|
||||
import com.sound.prankparty.Activity.PlaySoundActivity;
|
||||
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;
|
||||
private int color;
|
||||
|
||||
public AirHornRecyclerViewAdapter(Context context, List<SoundItem> soundItemList,int color) {
|
||||
this.context = context;
|
||||
this.soundItemList = soundItemList;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AirhonrViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_airhorn, parent, false);
|
||||
return new AirHornRecyclerViewAdapter.AirhonrViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull AirhonrViewHolder holder, int position) {
|
||||
|
||||
SoundItem soundItem = soundItemList.get(position);
|
||||
|
||||
holder.imageView.setBackgroundColor(color);
|
||||
|
||||
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_airhorn);
|
||||
textView = itemView.findViewById(R.id.item_textview_airhorn);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
package com.sound.prankparty.Adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
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.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.MainApplication;
|
||||
import com.sound.prankparty.Activity.PlaySoundActivity;
|
||||
import com.sound.prankparty.JSON.SoundItem;
|
||||
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;
|
||||
private final int[] colors;
|
||||
|
||||
public FavoriteRecyclerViewAdapter(Context context, Fragment fragment) {
|
||||
this.context = context;
|
||||
this.fragment = fragment;
|
||||
colors = new int[]{
|
||||
ContextCompat.getColor(context, R.color.color2),
|
||||
ContextCompat.getColor(context, R.color.color3),
|
||||
ContextCompat.getColor(context, R.color.color4),
|
||||
ContextCompat.getColor(context, R.color.color5),
|
||||
ContextCompat.getColor(context, R.color.color6),
|
||||
ContextCompat.getColor(context, R.color.color7)
|
||||
// 添加更多颜色
|
||||
};
|
||||
}
|
||||
|
||||
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());
|
||||
// 使用取模运算来循环使用颜色
|
||||
holder.imageView.setBackgroundColor(colors[position % colors.length]);
|
||||
|
||||
holder.imageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// 创建 SoundItem 对象并传递你想存入的值
|
||||
SoundItem soundItem = new SoundItem(favoriteSounds.getPath(), favoriteSounds.getImagePath(), favoriteSounds.getName());
|
||||
|
||||
Intent intent = new Intent(fragment.getContext(), PlaySoundActivity.class);
|
||||
intent.putExtra("1234",soundItem);
|
||||
fragment.startActivity(intent);
|
||||
}
|
||||
});
|
||||
|
||||
Glide.with(MainApplication.getContext())
|
||||
.asDrawable()
|
||||
.skipMemoryCache(true)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.load(favoriteSounds.getImagePath())
|
||||
.placeholder(R.mipmap.default_image)
|
||||
.error(R.mipmap.default_image)
|
||||
.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
package com.sound.prankparty.Adapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
|
||||
import com.sound.prankparty.Fragment.SoundFragment;
|
||||
import com.sound.prankparty.Fragment.RadioFragment;
|
||||
import com.sound.prankparty.Fragment.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();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,134 @@
|
||||
package com.sound.prankparty.Adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
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.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.sound.prankparty.Activity.PlaySoundActivity;
|
||||
import com.sound.prankparty.JSON.SoundItem;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.FavoriteSounds;
|
||||
import com.sound.prankparty.Room.FavoriteSoundsDao;
|
||||
import com.sound.prankparty.Room.SaveSounds;
|
||||
import com.sound.prankparty.Room.SaveSoundsDao;
|
||||
|
||||
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;
|
||||
private SaveSoundsDao saveSoundsDao;
|
||||
|
||||
public RadioRecyclerViewAdapter(Context context, Fragment fragment, FavoriteSoundsDao favoriteSoundsDao, SaveSoundsDao saveSoundsDao) {
|
||||
this.context = context;
|
||||
this.fragment = fragment;
|
||||
this.favoriteSoundsDao = favoriteSoundsDao;
|
||||
this.saveSoundsDao = saveSoundsDao;
|
||||
}
|
||||
|
||||
@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());
|
||||
|
||||
holder.root.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
// 创建 SoundItem 对象并传递你想存入的值
|
||||
SoundItem soundItem = new SoundItem(saveSound.getPath(), "", saveSound.getName());
|
||||
|
||||
Intent intent = new Intent(fragment.getContext(), PlaySoundActivity.class);
|
||||
intent.putExtra("1234", soundItem);
|
||||
fragment.startActivity(intent);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
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 {
|
||||
|
||||
private TextView title;
|
||||
private TextView date;
|
||||
private TextView time;
|
||||
private TextView duration;
|
||||
private ImageView favorite;
|
||||
private ConstraintLayout root;
|
||||
|
||||
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);
|
||||
root = itemView.findViewById(R.id.item_con);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
package com.sound.prankparty.Adapter;
|
||||
|
||||
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.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.sound.prankparty.Activity.AirHornActivity;
|
||||
import com.sound.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.color2),
|
||||
ContextCompat.getColor(context, R.color.color3),
|
||||
ContextCompat.getColor(context, R.color.color4),
|
||||
ContextCompat.getColor(context, R.color.color5),
|
||||
ContextCompat.getColor(context, R.color.color6),
|
||||
ContextCompat.getColor(context, R.color.color7)
|
||||
// 添加更多颜色
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@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]);
|
||||
// 假设 `colors[position % colors.length]` 是你要传递的颜色值
|
||||
int currentColor = 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("color", currentColor); // 添加颜色值到 Intent
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
package com.sound.prankparty.Fragment;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Room.AppDatabase;
|
||||
import com.sound.prankparty.Room.FavoriteSoundsDao;
|
||||
import com.sound.prankparty.Adapter.FavoriteRecyclerViewAdapter;
|
||||
import com.sound.prankparty.Utils.FavoriteSoundsViewModel;
|
||||
import com.sound.prankparty.Utils.ItemDecoration;
|
||||
import com.sound.prankparty.databinding.FragmentFavoriteBinding;
|
||||
|
||||
public class FavoriteFragment extends Fragment {
|
||||
|
||||
private AppDatabase appDatabase;
|
||||
private FavoriteSoundsDao favoriteSoundsDao;
|
||||
private FavoriteRecyclerViewAdapter favoriteRecyclerViewAdapter;
|
||||
private FavoriteSoundsViewModel viewModel;
|
||||
private FragmentFavoriteBinding binding;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
binding = FragmentFavoriteBinding.inflate(inflater, container, false);
|
||||
View view = binding.getRoot();
|
||||
|
||||
// 使用 ApplicationContext 来获取 ViewModel
|
||||
viewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(requireActivity().getApplication())).get(FavoriteSoundsViewModel.class);
|
||||
|
||||
binding.favoriteRecyclerview.setLayoutManager(new GridLayoutManager(getContext(), 3));
|
||||
|
||||
favoriteRecyclerViewAdapter = new FavoriteRecyclerViewAdapter(requireContext(), this);
|
||||
binding.favoriteRecyclerview.setAdapter(favoriteRecyclerViewAdapter);
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰
|
||||
ItemDecoration itemDecoration = new ItemDecoration(16, 19, 10);
|
||||
binding.favoriteRecyclerview.addItemDecoration(itemDecoration);
|
||||
|
||||
appDatabase = AppDatabase.getDatabase(requireContext());
|
||||
favoriteSoundsDao = appDatabase.favoriteSoundsDao();
|
||||
|
||||
// 观察 LiveData 的变化
|
||||
viewModel.getFavoriteSoundsLiveData().observe(getViewLifecycleOwner(), favoriteSoundsList -> {
|
||||
if (favoriteSoundsList == null || favoriteSoundsList.isEmpty()) {
|
||||
binding.favoriteRecyclerview.setVisibility(View.GONE);
|
||||
binding.fragmentFavoriteTips.setVisibility(View.VISIBLE);
|
||||
binding.fragmentFavoriteImage.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
binding.favoriteRecyclerview.setVisibility(View.VISIBLE);
|
||||
binding.fragmentFavoriteTips.setVisibility(View.GONE);
|
||||
binding.fragmentFavoriteImage.setVisibility(View.GONE);
|
||||
}
|
||||
favoriteRecyclerViewAdapter.updateData(favoriteSoundsList);
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// 触发数据刷新
|
||||
viewModel.refreshData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,333 @@
|
||||
package com.sound.prankparty.Fragment;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
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.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
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.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.sound.prankparty.Activity.NewRecordActivity;
|
||||
import com.sound.prankparty.Adapter.RadioRecyclerViewAdapter;
|
||||
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 com.sound.prankparty.databinding.FragmentRadioBinding;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormatSymbols;
|
||||
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 FragmentRadioBinding binding;
|
||||
private RadioRecyclerViewAdapter radioRecyclerViewAdapter;
|
||||
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) {
|
||||
// 使用 ViewBinding 初始化视图
|
||||
binding = FragmentRadioBinding.inflate(inflater, container, false);
|
||||
View view = binding.getRoot();
|
||||
|
||||
// 初始化数据库
|
||||
appDatabase = AppDatabase.getDatabase(requireContext());
|
||||
saveSoundsDao = appDatabase.saveSoundsDao();
|
||||
favoriteSoundsDao = appDatabase.favoriteSoundsDao();
|
||||
|
||||
// 初始化 RecyclerView
|
||||
binding.radioRecyclerview.setLayoutManager(new GridLayoutManager(getContext(), 1));
|
||||
radioRecyclerViewAdapter = new RadioRecyclerViewAdapter(requireContext(), this, favoriteSoundsDao,saveSoundsDao);
|
||||
binding.radioRecyclerview.setAdapter(radioRecyclerViewAdapter);
|
||||
|
||||
// 初始化 MyItemTouchHelperCallback
|
||||
myItemTouchHelperCallback = new MyItemTouchHelperCallback(this);
|
||||
itemTouchHelper = new ItemTouchHelper(myItemTouchHelperCallback);
|
||||
itemTouchHelper.attachToRecyclerView(binding.radioRecyclerview);
|
||||
|
||||
// 设置添加按钮的点击事件
|
||||
binding.fragmentRadioAdd.setOnClickListener(v -> showCustomBottomSheetDialog());
|
||||
|
||||
// 刷新数据
|
||||
refreshData();
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
refreshData();
|
||||
}
|
||||
|
||||
public void deleteItem(int position) {
|
||||
new Thread(() -> {
|
||||
SaveSounds sound = saveSoundsList.get(position);
|
||||
saveSoundsDao.deleteSound(sound);
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
refreshData();
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
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 -> {
|
||||
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.dismiss();
|
||||
});
|
||||
|
||||
// 设置选项2的点击事件
|
||||
dialogView.findViewById(R.id.option2).setOnClickListener(v -> {
|
||||
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_OPEN_DOCUMENT); // 改为 ACTION_OPEN_DOCUMENT
|
||||
intent.setType("audio/*"); // 设置 MIME 类型为音频
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE); // 限制为可打开的文件
|
||||
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);
|
||||
}
|
||||
|
||||
// 获取文件的最后修改时间
|
||||
long lastModifiedTime = getLastModifiedTime(requireContext(),audioUri);
|
||||
String[] lastModifiedDateTime = getDateTimeFromLastModified(lastModifiedTime);
|
||||
|
||||
long finalDuration = duration;
|
||||
new Thread(() -> {
|
||||
try {
|
||||
saveSoundsDao.insertSound(new SaveSounds(fileName, audioUri.toString(), lastModifiedDateTime[0], lastModifiedDateTime[1], formatDuration(finalDuration)));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// 在主线程中显示错误信息
|
||||
requireActivity().runOnUiThread(() ->
|
||||
Toast.makeText(requireContext(), "插入数据库失败: " + e.getMessage(), Toast.LENGTH_LONG).show());
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取文件名
|
||||
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();
|
||||
try {
|
||||
retriever.setDataSource(requireContext(), uri);
|
||||
String duration = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
|
||||
return duration != null ? Long.parseLong(duration) : 0;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(); // 可以记录日志或进行其他异常处理
|
||||
return 0;
|
||||
} finally {
|
||||
retriever.release();
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化时长
|
||||
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 long getLastModifiedTime(Context context, Uri uri) {
|
||||
long lastModifiedTime = 0;
|
||||
|
||||
if (uri != null && "content".equals(uri.getScheme())) {
|
||||
DocumentFile documentFile = DocumentFile.fromSingleUri(context, uri);
|
||||
if (documentFile != null && documentFile.exists()) {
|
||||
lastModifiedTime = documentFile.lastModified();
|
||||
}
|
||||
} else if (uri != null && "file".equals(uri.getScheme())) {
|
||||
File file = new File(uri.getPath());
|
||||
if (file.exists()) {
|
||||
lastModifiedTime = file.lastModified();
|
||||
}
|
||||
}
|
||||
|
||||
return lastModifiedTime;
|
||||
}
|
||||
|
||||
public static String[] getDateTimeFromLastModified(long lastModifiedTime) {
|
||||
// 自定义DateFormatSymbols以使用小写的am和pm
|
||||
DateFormatSymbols dfs = new DateFormatSymbols(Locale.ENGLISH);
|
||||
dfs.setAmPmStrings(new String[]{"am", "pm"});
|
||||
|
||||
// 使用自定义的DateFormatSymbols创建SimpleDateFormat
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMM yyyy", Locale.ENGLISH);
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat("hh:mma", Locale.ENGLISH);
|
||||
timeFormat.setDateFormatSymbols(dfs);
|
||||
|
||||
// 将最后修改时间转换为Date对象
|
||||
Date lastModifiedDate = new Date(lastModifiedTime);
|
||||
String date = dateFormat.format(lastModifiedDate);
|
||||
String time = timeFormat.format(lastModifiedDate);
|
||||
|
||||
// 返回日期和时间字符串
|
||||
return new String[]{date, time};
|
||||
}
|
||||
|
||||
// 刷新数据
|
||||
public void refreshData() {
|
||||
new Thread(() -> {
|
||||
saveSoundsList = saveSoundsDao.getAllSounds();
|
||||
requireActivity().runOnUiThread(() -> {
|
||||
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) binding.fragmentRadioAdd.getLayoutParams();
|
||||
if (saveSoundsList.isEmpty()) {
|
||||
binding.radioRecyclerview.setVisibility(View.GONE);
|
||||
binding.emptyRadioImage.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 {
|
||||
binding.radioRecyclerview.setVisibility(View.VISIBLE);
|
||||
binding.emptyRadioImage.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;
|
||||
}
|
||||
|
||||
binding.fragmentRadioAdd.setLayoutParams(layoutParams);
|
||||
radioRecyclerViewAdapter.updateData(saveSoundsList);
|
||||
});
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,124 @@
|
||||
package com.sound.prankparty.Fragment;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.sound.MainApplication;
|
||||
import com.sound.prankparty.Activity.PrivacyActivity;
|
||||
import com.sound.prankparty.Adapter.SoundRecyclerViewAdapter;
|
||||
import com.sound.prankparty.JSON.Category;
|
||||
import com.sound.prankparty.R;
|
||||
import com.sound.prankparty.Utils.ItemDecoration;
|
||||
import com.sound.prankparty.Utils.JsonParser;
|
||||
import com.sound.prankparty.Utils.LoadJSON;
|
||||
import com.sound.prankparty.databinding.FragmentSoundBinding;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SoundFragment extends Fragment {
|
||||
|
||||
private FragmentSoundBinding binding;
|
||||
private PackageInfo packageInfo;
|
||||
private String format;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
// 使用 ViewBinding 初始化视图
|
||||
binding = FragmentSoundBinding.inflate(inflater, container, false);
|
||||
View view = binding.getRoot();
|
||||
|
||||
// 设置 RecyclerView 的布局管理器和适配器
|
||||
binding.soundRecyclerview.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
||||
|
||||
// 从 assets 文件夹中读取 JSON 文件
|
||||
String jsonString = LoadJSON.loadJSONFromAsset("prank.json");
|
||||
// 解析读取的 String
|
||||
List<Category> categories = JsonParser.parseJson(jsonString);
|
||||
|
||||
binding.soundRecyclerview.setAdapter(new SoundRecyclerViewAdapter(getContext(), categories));
|
||||
|
||||
// 为 RecyclerView 添加自定义的间距装饰
|
||||
ItemDecoration itemDecoration = new ItemDecoration(16, 19, 10);
|
||||
binding.soundRecyclerview.addItemDecoration(itemDecoration);
|
||||
|
||||
// 设置返回按钮的点击事件
|
||||
binding.fragmentSoundSetting.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);
|
||||
TextView version = dialogView.findViewById(R.id.version_number);
|
||||
|
||||
//更新版本号
|
||||
try {
|
||||
packageInfo = MainApplication.getContext().getPackageManager().getPackageInfo(MainApplication.getContext().getPackageName(), 0);
|
||||
String versionName = packageInfo.versionName;
|
||||
format = String.format(getString(R.string.gp), packageInfo.packageName);
|
||||
version.setText(versionName);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
version.setText("1.0.0");
|
||||
format = String.format(getString(R.string.gp), "com.sound.prankparty");
|
||||
}
|
||||
|
||||
|
||||
dialogView.findViewById(R.id.privacy).setOnClickListener(v -> {
|
||||
// 处理选项 1
|
||||
Intent intent = new Intent(requireActivity(), PrivacyActivity.class);
|
||||
startActivity(intent);
|
||||
// 销毁 BottomSheetDialog 对象
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
dialogView.findViewById(R.id.share).setOnClickListener(v -> {
|
||||
|
||||
shareString(format);
|
||||
// 处理选项 2
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
dialogView.findViewById(R.id.version).setOnClickListener(v -> {
|
||||
|
||||
});
|
||||
|
||||
dialogView.findViewById(R.id.cancel_button).setOnClickListener(v -> {
|
||||
|
||||
// 处理取消按钮
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
bottomSheetDialog.setContentView(dialogView);
|
||||
bottomSheetDialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分享纯文本
|
||||
*
|
||||
* @param content 内容
|
||||
*/
|
||||
public void shareString(String content) {
|
||||
Intent sendIntent = new Intent();
|
||||
sendIntent.setAction(Intent.ACTION_SEND);
|
||||
sendIntent.putExtra(Intent.EXTRA_TEXT, content);//分享的文本内容
|
||||
sendIntent.setType("text/plain");
|
||||
startActivity(Intent.createChooser(sendIntent, "Share to"));
|
||||
}
|
||||
|
||||
}
|
||||
@ -18,11 +18,23 @@ public class SoundItem implements Serializable {
|
||||
return mp3Url;
|
||||
}
|
||||
|
||||
public void setMp3Url(String mp3Url) {
|
||||
this.mp3Url = mp3Url;
|
||||
}
|
||||
|
||||
public String getPreUrl() {
|
||||
return preUrl;
|
||||
}
|
||||
|
||||
public void setPreUrl(String preUrl) {
|
||||
this.preUrl = preUrl;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
import com.sound.prankparty.Application.MainApplication;
|
||||
import com.sound.MainApplication;
|
||||
|
||||
|
||||
// ItemDecoration 是一个自定义的 RecyclerView.ItemDecoration 类,用于在 RecyclerView 中为每个子项设置间距。
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.sound.prankparty.Utils;
|
||||
|
||||
import com.sound.prankparty.Application.MainApplication;
|
||||
import com.sound.MainApplication;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
@ -1,62 +1,38 @@
|
||||
package com.sound.prankparty.Utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.sound.prankparty.Fragment.RadioFragment;
|
||||
import com.sound.prankparty.R;
|
||||
|
||||
public class MyItemTouchHelperCallback extends ItemTouchHelper.SimpleCallback {
|
||||
|
||||
private float maxDistance; // 最大滑动距离
|
||||
private boolean isMaxSwiped = false; // 是否达到最大距离
|
||||
private RecyclerView.ViewHolder swipedViewHolder; // 被滑动的ViewHolder
|
||||
private RadioFragment radioFragment;
|
||||
|
||||
public MyItemTouchHelperCallback() {
|
||||
// 构造方法,初始化回调对象
|
||||
public MyItemTouchHelperCallback(RadioFragment fragment) {
|
||||
super(0, ItemTouchHelper.LEFT); // 只允许左滑
|
||||
this.radioFragment = fragment;
|
||||
}
|
||||
|
||||
// 处理移动事件的方法,这里不处理移动事件
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
|
||||
return false; // 不处理移动事件
|
||||
}
|
||||
|
||||
// 处理滑动事件的方法
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
// 当滑动项被完全滑出时,可以在这里处理
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
// 当滑动项被完全滑出时,执行相应操作,比如删除或编辑
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
radioFragment.deleteItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
|
||||
float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||
// 限制最大滑动距离
|
||||
maxDistance = recyclerView.getWidth() * 0.5f; // 最大滑动为RecyclerView宽度的50%
|
||||
if (dX < -maxDistance) {
|
||||
dX = -maxDistance;
|
||||
isMaxSwiped = true;
|
||||
swipedViewHolder = viewHolder;
|
||||
} else {
|
||||
isMaxSwiped = false;
|
||||
}
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
|
||||
// 阻止自动滑出,始终返回1.0f
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// 复原滑动项的方法
|
||||
public void restoreSwipedItem() {
|
||||
if (swipedViewHolder != null) {
|
||||
View itemView = swipedViewHolder.itemView;
|
||||
itemView.animate().translationX(0).setDuration(200).start();
|
||||
swipedViewHolder = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
9
app/src/main/res/drawable/create_sounds.xml
Normal file
9
app/src/main/res/drawable/create_sounds.xml
Normal file
File diff suppressed because one or more lines are too long
9
app/src/main/res/drawable/delete.xml
Normal file
9
app/src/main/res/drawable/delete.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="20dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="20"
|
||||
android:viewportHeight="20">
|
||||
<path
|
||||
android:pathData="M8.699,15.061C9.066,15.061 9.365,14.764 9.365,14.394L8.699,7.746C8.699,7.379 8.402,7.08 8.033,7.08C7.664,7.08 7.367,7.377 7.367,7.746L8.033,14.394C8.035,14.762 8.332,15.061 8.699,15.061ZM16.678,3.756H12.025V3.424C12.025,2.689 11.43,2.094 10.695,2.094H9.365C8.631,2.094 8.035,2.689 8.035,3.424V3.756H3.381C3.014,3.756 2.715,4.053 2.715,4.422C2.715,4.789 3.012,5.088 3.381,5.088H16.68C17.047,5.088 17.346,4.791 17.346,4.422C17.346,4.053 17.047,3.756 16.678,3.756ZM10.695,3.756H9.365V3.424H10.695V3.756ZM15.418,5.762C15.031,5.762 14.715,6.066 14.697,6.449L13.223,16.391H6.842L5.361,6.418H5.354C5.318,6.051 5.01,5.762 4.637,5.762C4.26,5.762 3.951,6.049 3.92,6.418H3.895L5.258,16.783C5.264,16.729 5.26,16.668 5.248,16.602C5.348,17.236 5.898,17.721 6.561,17.721H13.518C14.184,17.721 14.734,17.232 14.83,16.598C14.822,16.641 14.82,16.68 14.82,16.721L16.172,6.416H16.137C16.1,6.049 15.793,5.762 15.418,5.762ZM12.025,14.394L12.691,7.746C12.691,7.379 12.394,7.08 12.025,7.08C11.656,7.08 11.359,7.377 11.359,7.746L10.693,14.394C10.693,14.762 10.99,15.061 11.359,15.061C11.727,15.061 12.025,14.762 12.025,14.394Z"
|
||||
android:fillColor="#FF6565"/>
|
||||
</vector>
|
||||
8
app/src/main/res/drawable/gradient.xml
Normal file
8
app/src/main/res/drawable/gradient.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:angle="0"
|
||||
android:endColor="#80FFFFFF"
|
||||
android:startColor="#E6FFFFFF"/>
|
||||
|
||||
</shape>
|
||||
24
app/src/main/res/drawable/item_border.xml
Normal file
24
app/src/main/res/drawable/item_border.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 边框 -->
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="16dp" /> <!-- 圆角半径与item_round一致 -->
|
||||
<stroke
|
||||
android:width="0.1dp"
|
||||
android:color="#000000" /> <!-- 边框颜色为黑色 -->
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<!-- 背景 -->
|
||||
<item
|
||||
android:bottom="0dp"
|
||||
android:left="0dp"
|
||||
android:right="0dp"
|
||||
android:top="0dp">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="16dp" /> <!-- 圆角半径与item_round一致 -->
|
||||
<solid android:color="@android:color/transparent" /> <!-- 背景透明 -->
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
9
app/src/main/res/drawable/item_round.xml
Normal file
9
app/src/main/res/drawable/item_round.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="16dp" /> <!-- 圆角半径 -->
|
||||
<solid android:color="#FFFFFF" /> <!-- 背景颜色 -->
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
9
app/src/main/res/drawable/my_favorite.xml
Normal file
9
app/src/main/res/drawable/my_favorite.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="112dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="112"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12.73,19.14V5.63L9.37,19H7.21L3.58,5.58V18.86L0.68,19V1.17L5.84,1.02L8.82,12.16L11.67,1.43L16.38,1.14V18.86L12.73,19.14ZM19.83,23.27C19.45,23.27 18.97,23.22 18.41,23.13V20.32C19.01,20.35 19.48,20.37 19.83,20.37C21.24,20.37 21.94,19.71 21.94,18.4V17.73L18.08,5.66L21.73,5.49L23.62,13.96L25.42,5.56L28.47,5.54L25.01,18.76C24.53,20.49 23.83,21.67 22.9,22.31C21.99,22.95 20.97,23.27 19.83,23.27ZM36.6,8.03H34.94L35.06,5.49H36.6V5.25C36.6,4.3 36.65,3.54 36.76,2.97C36.89,2.38 37.2,1.88 37.68,1.48C38.17,1.08 38.93,0.88 39.96,0.88C40.93,0.88 41.69,1 42.24,1.24V3.26H41.49C40.85,3.26 40.44,3.43 40.24,3.78C40.07,4.14 39.98,4.62 39.98,5.25V5.49H42.36L42.21,8.03H39.98V18.86L36.6,19.14V8.03ZM46.27,19.31C45.69,19.31 45.17,19.14 44.71,18.78C44.24,18.42 43.88,17.93 43.63,17.32C43.37,16.7 43.24,16 43.24,15.23C43.24,13.49 43.83,12.26 45.02,11.56C46.22,10.84 47.61,10.43 49.19,10.34C49.19,9.47 49.14,8.83 49.03,8.42C48.91,8 48.64,7.79 48.21,7.79C47.84,7.79 47.56,7.94 47.37,8.22C47.18,8.51 47.06,8.88 47.01,9.33L43.72,8.75C43.88,7.52 44.39,6.64 45.23,6.11C46.08,5.58 47.07,5.32 48.21,5.32C49.67,5.32 50.75,5.7 51.47,6.47C52.21,7.24 52.58,8.24 52.58,9.47V16.46C52.58,17.21 52.7,18.01 52.94,18.86L49.65,19.14L49.27,17.49C48.98,18 48.55,18.43 47.99,18.78C47.43,19.14 46.86,19.31 46.27,19.31ZM47.83,16.91C48.1,16.91 48.32,16.85 48.5,16.72C48.69,16.59 48.92,16.38 49.19,16.1V12.35C48.39,12.35 47.75,12.57 47.27,13C46.79,13.43 46.55,14.1 46.55,15.02C46.55,15.62 46.66,16.1 46.87,16.43C47.09,16.75 47.41,16.91 47.83,16.91ZM57.75,19L53.99,5.78L58.02,5.49L59.72,14.13L61.67,5.92L64.71,5.63L60.85,19H57.75ZM70.67,19.31C69.05,19.31 67.8,18.67 66.92,17.39C66.06,16.11 65.63,14.41 65.63,12.28C65.63,10.17 66.06,8.48 66.92,7.22C67.79,5.95 69.04,5.32 70.67,5.32C72.28,5.32 73.53,5.95 74.41,7.22C75.31,8.48 75.76,10.17 75.76,12.28C75.76,14.39 75.31,16.1 74.41,17.39C73.53,18.67 72.28,19.31 70.67,19.31ZM70.67,16.82C71.39,16.82 71.85,16.38 72.06,15.5C72.27,14.62 72.37,13.54 72.37,12.26C72.37,10.98 72.27,9.9 72.06,9.02C71.85,8.14 71.39,7.7 70.67,7.7C69.95,7.7 69.49,8.11 69.3,8.94C69.11,9.78 69.01,10.79 69.01,11.99C69.01,13.46 69.11,14.64 69.3,15.52C69.49,16.38 69.95,16.82 70.67,16.82ZM78.04,5.78L81.4,5.49V7.67C81.88,6.98 82.47,6.43 83.18,6.02C83.9,5.58 84.81,5.37 85.91,5.37V8.66C85.34,8.66 84.58,8.76 83.63,8.97C82.71,9.16 81.96,9.5 81.4,10V18.86L78.04,19.14V5.78ZM87.77,3.76V0.28L91.13,0.04V3.62L87.77,3.76ZM87.75,19.14V5.78L91.11,5.49V18.86L87.75,19.14ZM98.66,19.26C97.57,19.26 96.65,18.99 95.9,18.45C95.15,17.89 94.77,16.9 94.77,15.5V8.03H92.9L93.04,5.49H94.87L95.2,2.56L98.13,2.15V5.49H100.91L100.77,8.03H98.15V15.47C98.15,15.95 98.27,16.3 98.51,16.5C98.75,16.71 99.11,16.82 99.57,16.82C99.83,16.82 100.26,16.77 100.87,16.67V19C100.8,19.02 100.55,19.06 100.1,19.14C99.67,19.22 99.19,19.26 98.66,19.26ZM106.99,19.31C105.39,19.31 104.17,18.68 103.32,17.42C102.47,16.14 102.05,14.44 102.05,12.33C102.05,10.18 102.48,8.48 103.35,7.22C104.21,5.95 105.47,5.32 107.11,5.32C108.68,5.32 109.88,5.95 110.71,7.22C111.55,8.48 111.96,10.18 111.96,12.33C111.96,12.46 111.94,12.55 111.89,12.62C111.84,12.66 111.82,12.7 111.82,12.71H105.41C105.41,13.75 105.55,14.7 105.82,15.57C106.09,16.42 106.51,16.84 107.07,16.84C107.69,16.84 108.15,16.48 108.46,15.76C108.76,15.04 108.92,14.66 108.94,14.63L111.48,15.59C111.15,16.74 110.61,17.66 109.87,18.33C109.14,18.98 108.18,19.31 106.99,19.31ZM108.65,10.77C108.65,9.81 108.52,9.05 108.27,8.49C108.01,7.93 107.61,7.65 107.07,7.65C106.79,7.65 106.53,7.78 106.27,8.06C106.02,8.33 105.81,8.7 105.65,9.18C105.49,9.66 105.41,10.19 105.41,10.77H108.65Z"
|
||||
android:fillColor="#181B3A"/>
|
||||
</vector>
|
||||
9
app/src/main/res/drawable/new_record.xml
Normal file
9
app/src/main/res/drawable/new_record.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="111dp"
|
||||
android:height="19dp"
|
||||
android:viewportWidth="111"
|
||||
android:viewportHeight="19">
|
||||
<path
|
||||
android:pathData="M9.08,18.14L3.82,6.89V17.86L0.68,18V0.14L4.35,-0L9.01,10.7V0.29L11.98,-0V17.86L9.08,18.14ZM19.43,18.31C17.83,18.31 16.61,17.68 15.76,16.42C14.91,15.14 14.49,13.44 14.49,11.33C14.49,9.18 14.92,7.48 15.78,6.22C16.65,4.95 17.9,4.32 19.55,4.32C21.12,4.32 22.32,4.95 23.15,6.22C23.98,7.48 24.4,9.18 24.4,11.33C24.4,11.46 24.38,11.55 24.33,11.62C24.28,11.66 24.26,11.7 24.26,11.71H17.85C17.85,12.75 17.98,13.7 18.26,14.57C18.53,15.42 18.94,15.84 19.5,15.84C20.13,15.84 20.59,15.48 20.9,14.76C21.2,14.04 21.36,13.66 21.38,13.63L23.92,14.59C23.58,15.74 23.05,16.66 22.31,17.33C21.58,17.98 20.62,18.31 19.43,18.31ZM21.09,9.77C21.09,8.81 20.96,8.05 20.7,7.49C20.45,6.93 20.05,6.65 19.5,6.65C19.23,6.65 18.97,6.78 18.71,7.06C18.46,7.33 18.25,7.7 18.09,8.18C17.93,8.66 17.85,9.19 17.85,9.77H21.09ZM28.16,18L25.4,4.75L28.83,4.49L29.98,12.14L31.69,4.78L34.5,4.49L35.96,12.05L37.42,4.78L40.16,4.63L37.06,18H34.35L32.82,9.24L30.92,18H28.16ZM47.69,4.78L51.05,4.49V6.67C51.53,5.98 52.12,5.43 52.83,5.02C53.55,4.58 54.46,4.37 55.56,4.37V7.66C54.99,7.66 54.23,7.76 53.28,7.97C52.35,8.16 51.61,8.5 51.05,9V17.86L47.69,18.14V4.78ZM61.69,18.31C60.09,18.31 58.87,17.68 58.02,16.42C57.17,15.14 56.75,13.44 56.75,11.33C56.75,9.18 57.18,7.48 58.04,6.22C58.91,4.95 60.16,4.32 61.81,4.32C63.38,4.32 64.58,4.95 65.41,6.22C66.24,7.48 66.66,9.18 66.66,11.33C66.66,11.46 66.63,11.55 66.59,11.62C66.54,11.66 66.51,11.7 66.51,11.71H60.11C60.11,12.75 60.24,13.7 60.51,14.57C60.79,15.42 61.2,15.84 61.76,15.84C62.39,15.84 62.85,15.48 63.15,14.76C63.46,14.04 63.62,13.66 63.63,13.63L66.18,14.59C65.84,15.74 65.31,16.66 64.57,17.33C63.83,17.98 62.87,18.31 61.69,18.31ZM63.35,9.77C63.35,8.81 63.22,8.05 62.96,7.49C62.71,6.93 62.31,6.65 61.76,6.65C61.49,6.65 61.23,6.78 60.97,7.06C60.71,7.33 60.51,7.7 60.35,8.18C60.19,8.66 60.11,9.19 60.11,9.77H63.35ZM72.87,18.31C71.84,18.31 70.96,17.99 70.23,17.35C69.51,16.71 68.96,15.86 68.59,14.81C68.23,13.75 68.04,12.61 68.04,11.38C68.04,10.16 68.22,9.02 68.57,7.94C68.94,6.87 69.49,6 70.23,5.33C70.96,4.66 71.87,4.32 72.94,4.32C73.75,4.32 74.48,4.53 75.12,4.94C75.78,5.34 76.29,5.91 76.66,6.65C77.03,7.38 77.23,8.22 77.26,9.17L74.07,9.31C74.07,9.25 74.03,8.99 73.97,8.54C73.92,8.1 73.8,7.73 73.61,7.44C73.43,7.15 73.2,7.01 72.91,7.01C72.27,7.01 71.87,7.45 71.69,8.33C71.51,9.19 71.43,10.17 71.43,11.26C71.43,12.33 71.51,13.3 71.69,14.18C71.88,15.05 72.32,15.48 73.01,15.48C73.87,15.48 74.32,14.63 74.35,12.94L77.19,13.25C76.98,14.91 76.56,16.18 75.94,17.04C75.31,17.89 74.29,18.31 72.87,18.31ZM83.77,18.31C82.15,18.31 80.91,17.67 80.03,16.39C79.16,15.11 78.73,13.41 78.73,11.28C78.73,9.17 79.16,7.48 80.03,6.22C80.89,4.95 82.14,4.32 83.77,4.32C85.39,4.32 86.63,4.95 87.51,6.22C88.41,7.48 88.86,9.17 88.86,11.28C88.86,13.39 88.41,15.1 87.51,16.39C86.63,17.67 85.39,18.31 83.77,18.31ZM83.77,15.82C84.49,15.82 84.95,15.38 85.16,14.5C85.37,13.62 85.47,12.54 85.47,11.26C85.47,9.98 85.37,8.9 85.16,8.02C84.95,7.14 84.49,6.7 83.77,6.7C83.05,6.7 82.59,7.11 82.4,7.94C82.21,8.78 82.11,9.79 82.11,10.99C82.11,12.46 82.21,13.64 82.4,14.52C82.59,15.38 83.05,15.82 83.77,15.82ZM91.14,4.78L94.5,4.49V6.67C94.98,5.98 95.58,5.43 96.28,5.02C97,4.58 97.91,4.37 99.02,4.37V7.66C98.44,7.66 97.68,7.76 96.74,7.97C95.81,8.16 95.06,8.5 94.5,9V17.86L91.14,18.14V4.78ZM104.14,18.31C101.54,18.31 100.25,15.96 100.25,11.26C100.25,8.81 100.57,7.04 101.21,5.95C101.85,4.86 102.85,4.32 104.21,4.32C104.78,4.32 105.33,4.51 105.86,4.9C106.39,5.26 106.78,5.73 107.01,6.29V0.43L110.4,-0V17.86L107.86,18.14L107.01,16.32C106.86,16.91 106.56,17.39 106.13,17.76C105.69,18.13 105.03,18.31 104.14,18.31ZM105.38,15.91C105.86,15.91 106.25,15.65 106.56,15.12C106.86,14.58 107.01,13.66 107.01,12.38V7.87C106.55,7.15 106.01,6.79 105.38,6.79C104.86,6.79 104.46,6.98 104.21,7.37C103.97,7.74 103.81,8.22 103.73,8.83C103.66,9.44 103.63,10.25 103.63,11.26C103.63,12.28 103.66,13.11 103.73,13.75C103.81,14.39 103.97,14.91 104.23,15.31C104.49,15.71 104.87,15.91 105.38,15.91Z"
|
||||
android:fillColor="#181B3A"/>
|
||||
</vector>
|
||||
@ -1,5 +1,29 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#4156C8" /> <!-- 设置圆形的填充颜色 -->
|
||||
<size android:width="60dp" android:height="60dp" /> <!-- 设置圆形的直径 -->
|
||||
<corners android:radius="30dp" /> <!-- 圆角半径设置为宽度或高度的一半,以形成圆形 -->
|
||||
</shape>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 外层圆环 -->
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#80AABCFF" /> <!-- 圆环的颜色 -->
|
||||
<!-- 外层圆环的直径:中心圆100dp + 空隙5dp*2 + 圆环10dp*2 = 130dp -->
|
||||
<size android:width="108dp" android:height="108dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<!-- 白色空隙层 -->
|
||||
<item android:top="5dp" android:bottom="5dp" android:left="5dp" android:right="5dp">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#FFFFFF" /> <!-- 空隙的颜色 -->
|
||||
<!-- 白色空隙层的直径:中心圆100dp + 空隙5dp*2 = 110dp -->
|
||||
<size android:width="102dp" android:height="102dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<!-- 中心圆 -->
|
||||
<item android:top="7dp" android:bottom="7dp" android:left="7dp" android:right="7dp">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#AAB2FF" /> <!-- 中心圆的颜色 -->
|
||||
<!-- 中心圆的直径:100dp -->
|
||||
<size android:width="100dp" android:height="100dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<!-- 背景部分 -->
|
||||
<item android:left="2dp" android:bottom="2dp">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#ABABAB" /> <!-- 背景颜色 -->
|
||||
<solid android:color="#EDEFFF" /> <!-- 背景颜色 -->
|
||||
<corners android:radius="16dp" /> <!-- 圆角半径 -->
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
19
app/src/main/res/drawable/round_play.xml
Normal file
19
app/src/main/res/drawable/round_play.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 外层圆环 -->
|
||||
<item>
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#CC505BC8" /> <!-- 圆环的颜色 -->
|
||||
<!-- 外层圆环的直径:中心圆100dp + 空隙5dp*2 + 圆环10dp*2 = 130dp -->
|
||||
<size android:width="110dp" android:height="110dp" />
|
||||
</shape>
|
||||
</item>
|
||||
<!-- 中心圆 -->
|
||||
<item android:top="5dp" android:bottom="5dp" android:left="5dp" android:right="5dp">
|
||||
<shape android:shape="oval">
|
||||
<solid android:color="#505BC8" /> <!-- 中心圆的颜色 -->
|
||||
<!-- 中心圆的直径:100dp -->
|
||||
<size android:width="100dp" android:height="100dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
33
app/src/main/res/drawable/rounded_border.xml
Normal file
33
app/src/main/res/drawable/rounded_border.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<!-- 阴影部分 -->
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<!-- 阴影颜色,增加不透明度 -->
|
||||
<solid android:color="#181B3A" />
|
||||
<corners android:radius="16dp" />
|
||||
<padding
|
||||
android:left="1dp"
|
||||
android:bottom="1dp"
|
||||
android:right="1dp"
|
||||
android:top="1dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<!-- 背景部分 -->
|
||||
<item android:left="0dp" android:bottom="0dp">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#FFFFFF" /> <!-- 背景颜色 -->
|
||||
<corners android:radius="16dp" /> <!-- 圆角半径 -->
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<!-- 边框部分 -->
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="#000000" /> <!-- 边框颜色和宽度 -->
|
||||
<corners android:radius="16dp" /> <!-- 圆角半径 -->
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@ -8,8 +8,8 @@
|
||||
<padding
|
||||
android:left="4dp"
|
||||
android:bottom="4dp"
|
||||
android:right="0dp"
|
||||
android:top="0dp" />
|
||||
android:right="1dp"
|
||||
android:top="1dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".FirstFragment.AirHornActivity">
|
||||
tools:context=".Activity.AirHornActivity">
|
||||
|
||||
|
||||
<ImageView
|
||||
@ -18,14 +18,17 @@
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/black_back" />
|
||||
|
||||
<ImageView
|
||||
<TextView
|
||||
android:id="@+id/air_horn_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginTop="18dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/sound_title" />
|
||||
android:text="Airhorn"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/air_horn_recyclerview"
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".Main.MainActivity">
|
||||
tools:context=".Activity.MainActivity">
|
||||
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
|
||||
@ -1,22 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".SecondFragment.NewRecordActivity">
|
||||
tools:context=".Activity.NewRecordActivity">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/new_record_back"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/setting" />
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:src="@drawable/black_back" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/new_record_title"
|
||||
@ -25,15 +26,17 @@
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/sound_title" />
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:src="@drawable/new_record" />
|
||||
|
||||
<com.airbnb.lottie.LottieAnimationView
|
||||
android:id="@+id/animation_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_below="@+id/new_record_title"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="50dp"
|
||||
app:layout_constraintTop_toTopOf="@+id/new_record_title"
|
||||
app:layout_constraintBottom_toTopOf="@+id/new_record_time"
|
||||
app:lottie_fileName="Animation.json"
|
||||
app:lottie_loop="true" />
|
||||
|
||||
@ -42,7 +45,10 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/animation_view"
|
||||
android:layout_centerHorizontal="true"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginTop="50dp"
|
||||
android:textSize="44sp"
|
||||
android:textColor="@color/blue"
|
||||
@ -50,13 +56,14 @@
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/new_record_record"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/new_record_time"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="50dp"
|
||||
android:layout_width="110dp"
|
||||
android:layout_height="110dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginBottom="100dp"
|
||||
android:background="@drawable/round"
|
||||
android:src="@drawable/microphone" />
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -69,6 +69,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:textColor="@color/white"
|
||||
android:text="Airhorn"
|
||||
android:textSize="17sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/rounded_background"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@ -113,11 +116,11 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/playback"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginTop="50dp"
|
||||
android:layout_marginBottom="100dp"
|
||||
android:background="@drawable/round"
|
||||
android:background="@drawable/round_play"
|
||||
android:src="@drawable/playback"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
26
app/src/main/res/layout/activity_privacy.xml
Normal file
26
app/src/main/res/layout/activity_privacy.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".Activity.PrivacyActivity">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/btn_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:src="@drawable/black_back"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
@ -7,82 +7,87 @@
|
||||
android:layout_height="match_parent"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
tools:context=".SecondFragment.SaveRecordActivity">
|
||||
tools:context=".Activity.SaveRecordActivity">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/save_record_back"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/black_back" />
|
||||
android:src="@drawable/black_back"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/save_record_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/sound_title" />
|
||||
android:src="@drawable/new_record"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/save_record_image"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_below="@+id/save_record_title"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="50dp"
|
||||
android:src="@mipmap/savesound" />
|
||||
android:src="@mipmap/savesound"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/save_record_title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/save_record_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/save_record_image"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="50dp"
|
||||
android:textSize="44sp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="00:00:00"
|
||||
android:textColor="@color/blue"
|
||||
android:text="00:00:00" />
|
||||
android:textSize="19sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/save_record_image" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/save_record_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/save_record_time"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:hint="@string/give_name"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="46dp"
|
||||
android:layout_marginEnd="46dp"
|
||||
android:background="@drawable/round_edit_text"
|
||||
android:layout_marginTop="50dp" />
|
||||
android:gravity="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/save_record_play"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/save_record_name"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="50dp"
|
||||
android:background="@drawable/round"
|
||||
android:src="@drawable/playback" />
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_marginBottom="80dp"
|
||||
android:background="@drawable/round_play"
|
||||
android:src="@drawable/playback"
|
||||
app:layout_constraintBottom_toTopOf="@+id/save_record_save"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/save_record_save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginBottom="46dp"
|
||||
android:backgroundTint="@color/blue"
|
||||
android:text="Save Sound"/>
|
||||
android:text="Save Sound"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -41,8 +41,8 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cancel_button"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp"
|
||||
android:src="@drawable/cancel"
|
||||
android:layout_below="@id/all_option"
|
||||
android:layout_marginTop="16dp"
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ThirdFragment.FavoriteFragment">
|
||||
tools:context=".Fragment.FavoriteFragment">
|
||||
|
||||
|
||||
<ImageView
|
||||
@ -13,7 +13,7 @@
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/sound_title" />
|
||||
android:src="@drawable/my_favorite" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/favorite_recyclerview"
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".SecondFragment.RadioFragment">
|
||||
tools:context=".Fragment.RadioFragment">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/fragment_sound_title"
|
||||
@ -12,7 +12,7 @@
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:src="@drawable/sound_title"
|
||||
android:src="@drawable/create_sounds"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".FirstFragment.SoundFragment">
|
||||
tools:context=".Fragment.SoundFragment">
|
||||
|
||||
|
||||
<ImageView
|
||||
|
||||
41
app/src/main/res/layout/item_airhorn.xml
Normal file
41
app/src/main/res/layout/item_airhorn.xml
Normal file
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rounded_border">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_imageview_airhorn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="127dp"
|
||||
android:scaleType="centerCrop" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_textview_airhorn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/black"
|
||||
android:textStyle="bold"
|
||||
android:text="Airhorn"
|
||||
android:textSize="10sp"
|
||||
android:shadowColor="#80FFFFFF"
|
||||
android:shadowDx="0.5"
|
||||
android:shadowDy="0.5"
|
||||
android:shadowRadius="1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -2,14 +2,25 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/rounded_border_shadow">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_imageview_favorite"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="110dp"
|
||||
android:background="@drawable/rounded_border_shadow"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_imageview_favorite"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="110dp" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_imageview_text"
|
||||
@ -17,10 +28,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="22dp"
|
||||
android:background="@color/tint"
|
||||
android:text="@string/app_name"
|
||||
android:gravity="center"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/item_imageview_favorite"
|
||||
app:layout_constraintEnd_toEndOf="@+id/item_imageview_favorite"
|
||||
app:layout_constraintStart_toStartOf="@id/item_imageview_favorite" />
|
||||
android:text="@string/app_name"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,24 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/item_radio_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/round_create">
|
||||
>
|
||||
|
||||
<!-- 滑动后显示的 ImageView -->
|
||||
<!-- <ImageView-->
|
||||
<!-- android:id="@+id/item_delete"-->
|
||||
<!-- android:layout_width="wrap_content"-->
|
||||
<!-- android:layout_height="wrap_content"-->
|
||||
<!-- android:src="@drawable/delete"-->
|
||||
<!-- android:layout_gravity="end|center_vertical" />-->
|
||||
|
||||
<!-- 可滑动的内容区 -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/item_con"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
android:background="@drawable/round_create"
|
||||
android:padding="12dp"
|
||||
android:layout_gravity="start">
|
||||
|
||||
<!-- 图片 -->
|
||||
<ImageView
|
||||
@ -26,9 +32,9 @@
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="60dp"
|
||||
android:src="@mipmap/savesound"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<!-- 标题 -->
|
||||
<TextView
|
||||
@ -37,21 +43,34 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:text="@string/snoring"
|
||||
app:layout_constraintEnd_toStartOf="@+id/duration"
|
||||
app:layout_constraintStart_toEndOf="@+id/item_imageview_radio"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/duration" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<!-- 日期 -->
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="date"
|
||||
android:text="23 May 2024"
|
||||
android:textColor="#ABABAB"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintStart_toEndOf="@+id/item_imageview_radio"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
app:layout_constraintEnd_toStartOf="@+id/duration" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||
|
||||
<!-- 竖线 -->
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="12dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="#ABABAB"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/date"
|
||||
app:layout_constraintStart_toEndOf="@+id/date"
|
||||
app:layout_constraintTop_toTopOf="@+id/date" />
|
||||
|
||||
<!-- 时间 -->
|
||||
<TextView
|
||||
@ -59,10 +78,12 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="time"
|
||||
app:layout_constraintStart_toEndOf="@+id/date"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/date" />
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="07:00pm"
|
||||
android:textColor="#ABABAB"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintStart_toEndOf="@+id/divider"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title" />
|
||||
|
||||
<!-- 时长 -->
|
||||
<TextView
|
||||
@ -70,6 +91,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="File duration"
|
||||
android:textColor="#ABABAB"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
@ -85,39 +107,4 @@
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!-- 左滑显示的 LinearLayout -->
|
||||
<LinearLayout
|
||||
android:id="@+id/item_linear"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="end"
|
||||
app:layout_constraintStart_toEndOf="@+id/item_con"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<!-- 编辑按钮 -->
|
||||
<TextView
|
||||
android:id="@+id/jianyi_zhiding"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="编辑"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#222222"
|
||||
android:background="#eaeaea" />
|
||||
|
||||
<!-- 删除按钮 -->
|
||||
<TextView
|
||||
android:id="@+id/jianyi_delete"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="删除"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#FFFFFF"
|
||||
android:background="#D52619" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@ -10,10 +10,10 @@
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="16dp"
|
||||
app:cardElevation="0dp"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_imageview_sound"
|
||||
@ -24,10 +24,17 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_textview_sound"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="70dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="6dp"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
android:textColor="@color/black"
|
||||
android:textStyle="bold"
|
||||
android:shadowColor="#80FFFFFF"
|
||||
android:shadowDx="0.5"
|
||||
android:shadowDy="0.5"
|
||||
android:shadowRadius="1"
|
||||
android:text="Airhorn"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
@ -5,23 +5,24 @@
|
||||
android:layout_centerHorizontal="true">
|
||||
|
||||
<!-- 第一个 ImageView 在最上面居中 -->
|
||||
<ImageView
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="12dp"
|
||||
android:src="@drawable/sound_title" />
|
||||
android:text="Settings"
|
||||
android:textSize="19sp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cancel_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:src="@drawable/setting" />
|
||||
|
||||
android:layout_marginRight="16dp"
|
||||
android:src="@drawable/cancel" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/privacy"
|
||||
@ -92,20 +93,15 @@
|
||||
android:text="Version Number" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version_number"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="1.0.0"/>
|
||||
android:text="1.0.0" />
|
||||
</LinearLayout>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
<!-- 底部的空白距离 -->
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/version"
|
||||
android:layout_marginTop="10dp"
|
||||
android:max="100"
|
||||
android:progress="0" />
|
||||
|
||||
|
||||
android:layout_height="30dp"
|
||||
android:layout_below="@+id/version" />
|
||||
</RelativeLayout>
|
||||
|
||||
BIN
app/src/main/res/mipmap-xxxhdpi/default_image.png
Normal file
BIN
app/src/main/res/mipmap-xxxhdpi/default_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 58 KiB |
@ -4,9 +4,12 @@
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="whitea">#9F2929</color>
|
||||
<color name="blue">#505BC8</color>
|
||||
<color name="tint">#ABABAB</color>
|
||||
<color name="color1">#9F2929</color>
|
||||
<color name="color2">#5164CC</color>
|
||||
<color name="color3">#405F1D</color>
|
||||
<color name="tint">#CCFFFFFF</color>
|
||||
<color name="color2">#EDA7FF</color>
|
||||
<color name="color3">#F6BB54</color>
|
||||
<color name="color4">#A0FFFC</color>
|
||||
<color name="color5">#FF8ACE</color>
|
||||
<color name="color6">#7FD788</color>
|
||||
<color name="color7">#9D9BFF</color>
|
||||
|
||||
</resources>
|
||||
@ -1,7 +1,8 @@
|
||||
<resources>
|
||||
<string name="app_name">PrankPartyDemo</string>
|
||||
<string name="app_name">PrankParty</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
<string name="give_name">Give your created sound a name</string>
|
||||
<string name="snoring">Snoring</string>
|
||||
<string name="gp">https://play.google.com/store/apps/details?id=%s</string>
|
||||
</resources>
|
||||
@ -19,6 +19,6 @@ dependencyResolutionManagement {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "PrankPartyDemo"
|
||||
rootProject.name = "PrankParty"
|
||||
include(":app")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user