V1.0.0(1)完成
BIN
app/FunnyPrankSounds.jks
Normal file
@ -15,7 +15,7 @@ android {
|
||||
targetSdk = 34
|
||||
versionCode = 1
|
||||
versionName = "1.0.0"
|
||||
setProperty("archivesBaseName", "Funny Prank Sounds" + versionName + "(${versionCode})_$timestamp")
|
||||
setProperty("archivesBaseName", "Funny Prank Sounds " + versionName + "(${versionCode})_$timestamp")
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
@ -53,4 +53,6 @@ dependencies {
|
||||
|
||||
implementation ("androidx.room:room-runtime:2.6.1")
|
||||
annotationProcessor ("androidx.room:room-compiler:2.6.1")
|
||||
|
||||
implementation("com.airbnb.android:lottie:6.5.0")
|
||||
}
|
||||
14
app/proguard-rules.pro
vendored
@ -18,4 +18,16 @@
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
#-renamesourcefileattribute SourceFile
|
||||
|
||||
-keepclassmembers class com.prank.funnypranksounds.MyApplication {
|
||||
public static final java.lang.String Database_Name;
|
||||
public static final int Database_Version;
|
||||
}
|
||||
-keepclassmembers class * {
|
||||
@androidx.room.Query <methods>;
|
||||
}
|
||||
-keep class com.prank.funnypranksounds.data.local.database.AppDatabase { *; }
|
||||
-keep class com.prank.funnypranksounds.data.local.entity.AudioData { *; }
|
||||
-keep class com.prank.funnypranksounds.data.local.dao.AudioDataDao { *; }
|
||||
-dontwarn javax.annotation.Nullable
|
||||
|
||||
@ -23,6 +23,12 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.FunnyPrankSounds"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".ui.activity.SaveAudioActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.activity.RecordAudioActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".ui.activity.AudioPlayerActivity"
|
||||
android:exported="false" />
|
||||
|
||||
@ -38,7 +38,6 @@ public class MyApplication extends Application {
|
||||
private void initDatabase() {
|
||||
AudioRepository imageRepository = new AudioRepository(getContext());
|
||||
List<AudioData> audioDataList = JsonParser.parseJson("prank.json");
|
||||
Log.d("appliacation", "data: " + audioDataList);
|
||||
imageRepository.insertAll(audioDataList);
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ package com.prank.funnypranksounds.data.local.dao;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.room.Dao;
|
||||
import androidx.room.Delete;
|
||||
import androidx.room.Insert;
|
||||
import androidx.room.Query;
|
||||
import androidx.room.Update;
|
||||
@ -16,9 +17,15 @@ public interface AudioDataDao {
|
||||
@Insert
|
||||
void insertAll(List<AudioData> audioDataList);
|
||||
|
||||
@Insert
|
||||
void insert(AudioData audioData);
|
||||
|
||||
@Update
|
||||
void update(AudioData audioData);
|
||||
|
||||
@Delete
|
||||
void delete(AudioData audioData);
|
||||
|
||||
@Query("SELECT * FROM AudioData WHERE id IN (SELECT MIN(id) FROM AudioData GROUP BY categoryName)")
|
||||
LiveData<List<AudioData>> getFirstCategory();
|
||||
|
||||
@ -27,4 +34,10 @@ public interface AudioDataDao {
|
||||
|
||||
@Query("SELECT * FROM AudioData WHERE isFavorite = 1")
|
||||
LiveData<List<AudioData>> getFavorite();
|
||||
|
||||
@Query("SELECT * FROM AudioData WHERE isExternal = 1")
|
||||
LiveData<List<AudioData>> getExternal();
|
||||
|
||||
@Query("SELECT COUNT(*) FROM AudioData WHERE mp3Url = :uri")
|
||||
int getCount(String uri);
|
||||
}
|
||||
|
||||
@ -16,14 +16,16 @@ public class AudioData implements Serializable {
|
||||
private String mp3Url;
|
||||
private String preUrl;
|
||||
private boolean isFavorite;
|
||||
private boolean isExternal;
|
||||
|
||||
public AudioData(String categoryName, String categoryUrl, String title, String mp3Url, String preUrl, boolean isFavorite) {
|
||||
public AudioData(String categoryName, String categoryUrl, String title, String mp3Url, String preUrl, boolean isFavorite, boolean isExternal) {
|
||||
this.categoryName = categoryName;
|
||||
this.categoryUrl = categoryUrl;
|
||||
this.title = title;
|
||||
this.mp3Url = mp3Url;
|
||||
this.preUrl = preUrl;
|
||||
this.isFavorite = isFavorite;
|
||||
this.isExternal = isExternal;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@ -81,4 +83,12 @@ public class AudioData implements Serializable {
|
||||
public void setFavorite(boolean favorite) {
|
||||
isFavorite = favorite;
|
||||
}
|
||||
|
||||
public boolean isExternal() {
|
||||
return isExternal;
|
||||
}
|
||||
|
||||
public void setExternal(boolean external) {
|
||||
isExternal = external;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.prank.funnypranksounds.data.repository;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import androidx.lifecycle.LiveData;
|
||||
|
||||
@ -9,20 +11,28 @@ import com.prank.funnypranksounds.data.local.database.AppDatabase;
|
||||
import com.prank.funnypranksounds.data.local.entity.AudioData;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class AudioRepository {
|
||||
|
||||
private final AudioDataDao dao;
|
||||
private final ExecutorService executorService;
|
||||
|
||||
public AudioRepository(Context context) {
|
||||
AppDatabase appDatabase = AppDatabase.getInstance(context);
|
||||
dao = appDatabase.audioDataDao();
|
||||
executorService = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
|
||||
public void insertAll(List<AudioData> audioDataList) {
|
||||
new Thread(() -> dao.insertAll(audioDataList)).start();
|
||||
}
|
||||
|
||||
public void insert(AudioData audioData) {
|
||||
new Thread(() -> dao.insert(audioData)).start();
|
||||
}
|
||||
|
||||
public void update(AudioData audioData) {
|
||||
new Thread(() -> dao.update(audioData)).start();
|
||||
}
|
||||
@ -39,4 +49,23 @@ public class AudioRepository {
|
||||
return dao.getFavorite();
|
||||
}
|
||||
|
||||
public void getCountAsync(String uri, CountCallback callback) {
|
||||
executorService.execute(() -> {
|
||||
int count = dao.getCount(uri);
|
||||
new Handler(Looper.getMainLooper()).post(() -> callback.onCountFetched(count));
|
||||
});
|
||||
}
|
||||
|
||||
public interface CountCallback {
|
||||
void onCountFetched(int count);
|
||||
}
|
||||
|
||||
public LiveData<List<AudioData>> getExternal() {
|
||||
return dao.getExternal();
|
||||
}
|
||||
|
||||
public void delete(AudioData audioData){
|
||||
new Thread(() -> dao.delete(audioData)).start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ public class MainActivity extends AppCompatActivity {
|
||||
int iconResId = getIconResource(tab.getPosition(), isSelected);
|
||||
tabBinding.imageView.setImageResource(iconResId);
|
||||
|
||||
int textColor = isSelected ? getResources().getColor(R.color.black, null) : getResources().getColor(R.color.gray, null);
|
||||
int textColor = isSelected ? getResources().getColor(R.color.yellow, null) : getResources().getColor(R.color.gray, null);
|
||||
tabBinding.text.setTextColor(textColor);
|
||||
}
|
||||
}
|
||||
@ -114,17 +114,17 @@ public class MainActivity extends AppCompatActivity {
|
||||
switch (position) {
|
||||
case 0:
|
||||
tabCustomBinding.imageView.setImageResource(R.drawable.category);
|
||||
tabCustomBinding.text.setText("Category");
|
||||
tabCustomBinding.text.setTextColor(getResources().getColor(R.color.black, null));
|
||||
tabCustomBinding.text.setText(R.string.category);
|
||||
tabCustomBinding.text.setTextColor(getResources().getColor(R.color.yellow, null));
|
||||
break;
|
||||
case 1:
|
||||
tabCustomBinding.imageView.setImageResource(R.drawable.audio);
|
||||
tabCustomBinding.text.setText("Audio");
|
||||
tabCustomBinding.imageView.setImageResource(R.drawable.un_audio);
|
||||
tabCustomBinding.text.setText(R.string.audio);
|
||||
tabCustomBinding.text.setTextColor(getResources().getColor(R.color.gray, null));
|
||||
break;
|
||||
case 2:
|
||||
tabCustomBinding.imageView.setImageResource(R.drawable.un_collection);
|
||||
tabCustomBinding.text.setText("Collection");
|
||||
tabCustomBinding.text.setText(R.string.collection);
|
||||
tabCustomBinding.text.setTextColor(getResources().getColor(R.color.gray, null));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -0,0 +1,155 @@
|
||||
package com.prank.funnypranksounds.ui.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 androidx.activity.EdgeToEdge;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.prank.funnypranksounds.R;
|
||||
import com.prank.funnypranksounds.databinding.ActivityRecordAudioBinding;
|
||||
import com.prank.funnypranksounds.utils.AudioUtils;
|
||||
import com.prank.funnypranksounds.viewmodel.AudioViewModel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class RecordAudioActivity extends AppCompatActivity {
|
||||
|
||||
private ActivityRecordAudioBinding binding;
|
||||
private boolean isStarted;
|
||||
private long time;
|
||||
private final Handler handler = new Handler();
|
||||
private MediaRecorder mediaRecorder;
|
||||
private File outputFile;
|
||||
|
||||
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 200;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityRecordAudioBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
EdgeToEdge.enable(this);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
||||
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||
return insets;
|
||||
});
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
|
||||
binding.voice.setOnClickListener(v -> {
|
||||
if (ContextCompat.checkSelfPermission(RecordAudioActivity.this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(RecordAudioActivity.this, new String[]{Manifest.permission.RECORD_AUDIO}, REQUEST_RECORD_AUDIO_PERMISSION);
|
||||
} else {
|
||||
toggleRecording();
|
||||
}
|
||||
});
|
||||
|
||||
binding.back.setOnClickListener(v -> onBackPressed());
|
||||
}
|
||||
|
||||
private void toggleRecording() {
|
||||
if (isStarted) {
|
||||
stopRecording();
|
||||
} else {
|
||||
startRecording();
|
||||
}
|
||||
isStarted = !isStarted;
|
||||
}
|
||||
|
||||
private final Runnable updateTimeTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
long elapsedTime = currentTime - time;
|
||||
binding.time.setText(AudioUtils.formatTime(elapsedTime));
|
||||
handler.postDelayed(this, 1000);
|
||||
}
|
||||
};
|
||||
|
||||
private void startRecording() {
|
||||
try {
|
||||
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();
|
||||
|
||||
time = System.currentTimeMillis();
|
||||
handler.post(updateTimeTask);
|
||||
binding.animationView.playAnimation();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopRecording() {
|
||||
if (mediaRecorder != null) {
|
||||
mediaRecorder.stop();
|
||||
mediaRecorder.release();
|
||||
mediaRecorder = null;
|
||||
}
|
||||
|
||||
handler.removeCallbacks(updateTimeTask);
|
||||
binding.animationView.cancelAnimation();
|
||||
binding.animationView.setFrame(0);
|
||||
binding.time.setText(R.string._00_00_00);
|
||||
|
||||
Intent intent = new Intent(RecordAudioActivity.this, SaveAudioActivity.class);
|
||||
intent.putExtra("audioFilePath", outputFile.getAbsolutePath());
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
if (isStarted) {
|
||||
if (mediaRecorder != null) {
|
||||
mediaRecorder.stop();
|
||||
mediaRecorder.release();
|
||||
mediaRecorder = null;
|
||||
}
|
||||
deleteRecordingFile();
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
private void deleteRecordingFile() {
|
||||
if (outputFile != null && outputFile.exists()) {
|
||||
boolean deleted = outputFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
package com.prank.funnypranksounds.ui.activity;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.prank.funnypranksounds.R;
|
||||
import com.prank.funnypranksounds.data.local.database.AppDatabase;
|
||||
import com.prank.funnypranksounds.data.local.entity.AudioData;
|
||||
import com.prank.funnypranksounds.databinding.ActivitySaveAudioBinding;
|
||||
import com.prank.funnypranksounds.utils.AudioUtils;
|
||||
import com.prank.funnypranksounds.viewmodel.AudioViewModel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class SaveAudioActivity extends AppCompatActivity {
|
||||
|
||||
private ActivitySaveAudioBinding binding;
|
||||
private AudioViewModel audioViewModel;
|
||||
private String audioFilePath;
|
||||
private String inputText;
|
||||
private MediaPlayer mediaPlayer;
|
||||
private boolean isPlaying;
|
||||
private int duration;
|
||||
private boolean isSaved;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivitySaveAudioBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
EdgeToEdge.enable(this);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
|
||||
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
|
||||
return insets;
|
||||
});
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
audioFilePath = getIntent().getStringExtra("audioFilePath");
|
||||
if (audioFilePath == null) {
|
||||
Toast.makeText(this, "The audio file path is invalid", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
File audioFile = new File(audioFilePath);
|
||||
if (!audioFile.exists()) {
|
||||
Toast.makeText(this, "Audio file does not exist", Toast.LENGTH_SHORT).show();
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
audioViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(getApplication()))
|
||||
.get(AudioViewModel.class);
|
||||
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
binding.back.setOnClickListener(v -> handleBackPressed());
|
||||
binding.play.setOnClickListener(v -> playOrPauseAudio());
|
||||
|
||||
binding.save.setOnClickListener(v -> {
|
||||
inputText = binding.editText.getText().toString();
|
||||
if (inputText.trim().isEmpty()) {
|
||||
Toast.makeText(getApplicationContext(), "The name cannot be empty", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
|
||||
audioViewModel.insert(new AudioData(inputText, audioFilePath, inputText, audioFilePath, "", false, true));
|
||||
|
||||
isSaved = true;
|
||||
|
||||
Intent intent = new Intent(SaveAudioActivity.this, MainActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
});
|
||||
|
||||
displayAudioDuration();
|
||||
|
||||
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
handleBackPressed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void displayAudioDuration() {
|
||||
if (audioFilePath != null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioFilePath);
|
||||
mediaPlayer.prepare();
|
||||
|
||||
duration = mediaPlayer.getDuration();
|
||||
binding.time.setText(AudioUtils.formatTime(duration));
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "Unable to load audio", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this, "The audio file path is invalid", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBackPressed() {
|
||||
deleteRecordingFile();
|
||||
finish();
|
||||
}
|
||||
|
||||
private void deleteRecordingFile() {
|
||||
File file = new File(audioFilePath);
|
||||
if (file.exists()) {
|
||||
boolean deleted = file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void playOrPauseAudio() {
|
||||
if (isPlaying) {
|
||||
mediaPlayer.pause();
|
||||
binding.play.setImageResource(R.drawable.play);
|
||||
isPlaying = false;
|
||||
} else {
|
||||
if (mediaPlayer == null) {
|
||||
mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(audioFilePath);
|
||||
mediaPlayer.prepare();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(this, "Unable to play audio", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mediaPlayer.start();
|
||||
binding.play.setImageResource(R.drawable.pause);
|
||||
isPlaying = true;
|
||||
|
||||
mediaPlayer.setOnCompletionListener(mp -> {
|
||||
Toast.makeText(this, "Play completed", Toast.LENGTH_SHORT).show();
|
||||
binding.play.setImageResource(R.drawable.play);
|
||||
isPlaying = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mediaPlayer != null) {
|
||||
if (isPlaying) {
|
||||
mediaPlayer.stop();
|
||||
}
|
||||
mediaPlayer.release();
|
||||
mediaPlayer = null;
|
||||
}
|
||||
if (!isSaved) {
|
||||
deleteRecordingFile();
|
||||
}
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,7 @@ import com.prank.funnypranksounds.databinding.ActivitySplashBinding;
|
||||
public class SplashActivity extends AppCompatActivity {
|
||||
|
||||
private ActivitySplashBinding binding;
|
||||
private static final long TOTAL_TIME = 1000;
|
||||
private static final long TOTAL_TIME = 3000;
|
||||
private CountDownTimer countDownTimer;
|
||||
|
||||
@Override
|
||||
|
||||
@ -10,6 +10,8 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
@ -29,6 +31,7 @@ public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.ViewHolder>
|
||||
private final Context context;
|
||||
private final Activity activity;
|
||||
private final int type;
|
||||
private final int[] colors;
|
||||
|
||||
public AudioAdapter(List<AudioData> audioDataList, AudioViewModel audioViewModel, Context context, Activity activity, int type) {
|
||||
this.context = context;
|
||||
@ -36,6 +39,16 @@ public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.ViewHolder>
|
||||
this.audioDataList = audioDataList;
|
||||
this.activity = activity;
|
||||
this.type = type;
|
||||
|
||||
colors = new int[]{
|
||||
R.color.color1,
|
||||
R.color.color2,
|
||||
R.color.color3,
|
||||
R.color.color4,
|
||||
R.color.color5,
|
||||
R.color.color6,
|
||||
R.color.color7
|
||||
};
|
||||
}
|
||||
|
||||
public void updateData(List<AudioData> newAudioDataList) {
|
||||
@ -61,7 +74,7 @@ public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.ViewHolder>
|
||||
name = audioData.getTitle();
|
||||
}
|
||||
|
||||
holder.bind(audioData, name);
|
||||
holder.bind(audioData, name,position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -73,20 +86,27 @@ public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.ViewHolder>
|
||||
ImageView imageView;
|
||||
ImageView like;
|
||||
TextView textView;
|
||||
ConstraintLayout constraintLayout;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
imageView = itemView.findViewById(R.id.imageView);
|
||||
like = itemView.findViewById(R.id.like);
|
||||
textView = itemView.findViewById(R.id.textView);
|
||||
constraintLayout = itemView.findViewById(R.id.main);
|
||||
}
|
||||
|
||||
void bind(AudioData audioData, String name) {
|
||||
String audioDataImagePath = audioData.getCategoryUrl();
|
||||
void bind(AudioData audioData, String name,int position) {
|
||||
String audioDataImagePath = "";
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
setItemText(name);
|
||||
|
||||
if (type == 0 || type == 1) {
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
setItemText(name);
|
||||
constraintLayout.setBackgroundTintList(ContextCompat.getColorStateList(context, colors[position % colors.length]));
|
||||
|
||||
if (type == 0) {
|
||||
audioDataImagePath = audioData.getCategoryUrl();
|
||||
}else if (type == 1){
|
||||
audioDataImagePath = audioData.getPreUrl();
|
||||
}
|
||||
|
||||
loadImage(audioDataImagePath);
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
package com.prank.funnypranksounds.ui.callback;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class AudioItemCallback extends ItemTouchHelper.SimpleCallback {
|
||||
|
||||
private final OnItemSwipeListener listener;
|
||||
|
||||
public AudioItemCallback(OnItemSwipeListener listener) {
|
||||
super(0, ItemTouchHelper.LEFT);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
int position = viewHolder.getAdapterPosition();
|
||||
if (listener != null) {
|
||||
listener.onItemSwiped(position);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnItemSwipeListener {
|
||||
void onItemSwiped(int position);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,66 +1,219 @@
|
||||
package com.prank.funnypranksounds.ui.fragment;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
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.fragment.app.Fragment;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.prank.funnypranksounds.R;
|
||||
import com.prank.funnypranksounds.data.local.entity.AudioData;
|
||||
import com.prank.funnypranksounds.data.repository.AudioRepository;
|
||||
import com.prank.funnypranksounds.databinding.FragmentAudioBinding;
|
||||
import com.prank.funnypranksounds.ui.activity.RecordAudioActivity;
|
||||
import com.prank.funnypranksounds.ui.adapter.AudioAdapter;
|
||||
import com.prank.funnypranksounds.ui.callback.AudioItemCallback;
|
||||
import com.prank.funnypranksounds.utils.AudioUtils;
|
||||
import com.prank.funnypranksounds.viewmodel.AudioViewModel;
|
||||
|
||||
/**
|
||||
* A simple {@link Fragment} subclass.
|
||||
* Use the {@link AudioFragment#newInstance} factory method to
|
||||
* create an instance of this fragment.
|
||||
*/
|
||||
public class AudioFragment extends Fragment {
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
private static final String ARG_PARAM1 = "param1";
|
||||
private static final String ARG_PARAM2 = "param2";
|
||||
public class AudioFragment extends Fragment implements AudioItemCallback.OnItemSwipeListener {
|
||||
|
||||
// TODO: Rename and change types of parameters
|
||||
private String mParam1;
|
||||
private String mParam2;
|
||||
|
||||
public AudioFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @param param1 Parameter 1.
|
||||
* @param param2 Parameter 2.
|
||||
* @return A new instance of fragment AudioFragment.
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
public static AudioFragment newInstance(String param1, String param2) {
|
||||
AudioFragment fragment = new AudioFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARG_PARAM1, param1);
|
||||
args.putString(ARG_PARAM2, param2);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
mParam1 = getArguments().getString(ARG_PARAM1);
|
||||
mParam2 = getArguments().getString(ARG_PARAM2);
|
||||
}
|
||||
}
|
||||
private FragmentAudioBinding binding;
|
||||
private AudioAdapter adapter;
|
||||
private AudioViewModel audioViewModel;
|
||||
private Uri audioUri;
|
||||
private String fileName;
|
||||
private List<AudioData> audioDataList = new ArrayList<>();
|
||||
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) {
|
||||
// Inflate the layout for this fragment
|
||||
return inflater.inflate(R.layout.fragment_audio, container, false);
|
||||
|
||||
binding = FragmentAudioBinding.inflate(inflater, container, false);
|
||||
|
||||
initData();
|
||||
initEvent();
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
private void initData() {
|
||||
audioViewModel = new ViewModelProvider(this, new ViewModelProvider.AndroidViewModelFactory(requireActivity().getApplication()))
|
||||
.get(AudioViewModel.class);
|
||||
|
||||
|
||||
binding.recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 1));
|
||||
adapter = new AudioAdapter(audioDataList, audioViewModel, requireContext(), requireActivity(), 1);
|
||||
binding.recyclerView.setAdapter(adapter);
|
||||
|
||||
AudioItemCallback callback = new AudioItemCallback(this);
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
|
||||
itemTouchHelper.attachToRecyclerView(binding.recyclerView);
|
||||
}
|
||||
|
||||
private void initEvent() {
|
||||
binding.add.setOnClickListener(v -> showCustomBottomSheetDialog());
|
||||
loadExternal();
|
||||
}
|
||||
|
||||
private void loadExternal() {
|
||||
audioViewModel
|
||||
.getExternal()
|
||||
.observe(getViewLifecycleOwner(), new Observer<List<AudioData>>() {
|
||||
@Override
|
||||
public void onChanged(List<AudioData> dataList) {
|
||||
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) binding.add.getLayoutParams();
|
||||
if (dataList.isEmpty()) {
|
||||
binding.audioBackground.setVisibility(View.VISIBLE);
|
||||
|
||||
layoutParams.topToBottom = ConstraintLayout.LayoutParams.UNSET;
|
||||
layoutParams.bottomToTop = ConstraintLayout.LayoutParams.UNSET;
|
||||
layoutParams.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
} else {
|
||||
binding.audioBackground.setVisibility(View.GONE);
|
||||
|
||||
layoutParams.topToTop = ConstraintLayout.LayoutParams.UNSET;
|
||||
layoutParams.bottomToTop = ConstraintLayout.LayoutParams.UNSET;
|
||||
layoutParams.topToBottom = R.id.recycler_view;
|
||||
}
|
||||
layoutParams.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
layoutParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
layoutParams.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID;
|
||||
audioDataList = dataList;
|
||||
adapter.updateData(dataList);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showCustomBottomSheetDialog() {
|
||||
BottomSheetDialog bottomSheetDialog = new BottomSheetDialog(requireContext());
|
||||
View dialogView = LayoutInflater.from(requireContext()).inflate(R.layout.bottom_dialog, null);
|
||||
|
||||
bottomSheetDialog.setCanceledOnTouchOutside(false);
|
||||
|
||||
dialogView.findViewById(R.id.import_audio).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();
|
||||
});
|
||||
|
||||
dialogView.findViewById(R.id.create).setOnClickListener(v -> {
|
||||
Intent intent = new Intent(getActivity(), RecordAudioActivity.class);
|
||||
startActivity(intent);
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
dialogView.findViewById(R.id.cancel_button).setOnClickListener(v -> {
|
||||
bottomSheetDialog.dismiss();
|
||||
});
|
||||
|
||||
bottomSheetDialog.setContentView(dialogView);
|
||||
bottomSheetDialog.show();
|
||||
}
|
||||
|
||||
private void openAudioPicker() {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
intent.setType("audio/*");
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
startActivityForResult(intent, REQUEST_CODE_PICK_AUDIO);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode != REQUEST_CODE_PICK_AUDIO || resultCode != RESULT_OK || data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
audioUri = data.getData();
|
||||
if (audioUri == null) {
|
||||
Toast.makeText(requireContext(), "The file could not be found.", Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
|
||||
fileName = AudioUtils.getFileName(audioUri, requireActivity());
|
||||
|
||||
try {
|
||||
audioViewModel.getCountAsync(audioUri.toString(), new AudioRepository.CountCallback() {
|
||||
@Override
|
||||
public void onCountFetched(int count) {
|
||||
if (count > 0) {
|
||||
Toast.makeText(requireContext(), "This file has been imported and cannot be imported again", Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
audioViewModel.insert(new AudioData(fileName, audioUri.toString(), fileName, audioUri.toString(), "", false, true));
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Toast.makeText(requireContext(), "Failed to insert database: " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSwiped(int position) {
|
||||
deleteItem(position);
|
||||
}
|
||||
|
||||
public void deleteItem(int position) {
|
||||
AudioData audioData = audioDataList.get(position);
|
||||
try {
|
||||
audioViewModel.delete(audioData);
|
||||
Toast.makeText(getContext(), "Audio deleted successfully.", Toast.LENGTH_SHORT).show();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(getContext(), "Failed to delete audio.", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
package com.prank.funnypranksounds.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
public class AudioUtils {
|
||||
|
||||
public static String getFileName(Uri uri, Activity activity) {
|
||||
String result = null;
|
||||
if (Objects.equals(uri.getScheme(), "content")) {
|
||||
try (Cursor cursor = activity.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;
|
||||
}
|
||||
|
||||
public static 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(Locale.getDefault(),"%02d:%02d:%02d", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
}
|
||||
@ -55,7 +55,7 @@ public class JsonParser {
|
||||
String mp3Url = itemObject.getString("mp3Url");
|
||||
String preUrl = itemObject.getString("preUrl");
|
||||
|
||||
audioDataList.add(new AudioData(name, url, title, mp3Url, preUrl, false));
|
||||
audioDataList.add(new AudioData(name, url, title, mp3Url, preUrl, false,false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -20,6 +20,10 @@ public class AudioViewModel extends AndroidViewModel {
|
||||
audioRepository = new AudioRepository(application);
|
||||
}
|
||||
|
||||
public void insert(AudioData audioData) {
|
||||
audioRepository.insert(audioData);
|
||||
}
|
||||
|
||||
public void update(AudioData audioData) {
|
||||
audioRepository.update(audioData);
|
||||
}
|
||||
@ -43,4 +47,16 @@ public class AudioViewModel extends AndroidViewModel {
|
||||
return isFavorite;
|
||||
}
|
||||
|
||||
public void getCountAsync(String uri, AudioRepository.CountCallback callback) {
|
||||
audioRepository.getCountAsync(uri, callback);
|
||||
}
|
||||
|
||||
public LiveData<List<AudioData>> getExternal() {
|
||||
return audioRepository.getExternal();
|
||||
}
|
||||
|
||||
public void delete(AudioData audioData){
|
||||
audioRepository.delete(audioData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
33
app/src/main/res/drawable/add.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M33,7.263C30.321,5.819 27.256,5 24,5C13.507,5 5,13.507 5,24C5,34.493 13.507,43 24,43C26.858,43 29.569,42.369 32,41.239"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M31,30L43,30"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M15,22L22,29L41,11"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M37,24V36"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@ -8,20 +8,20 @@
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M32,14L26,16.969V31.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M20.5,31.5m-5.5,0a5.5,5.5 0,1 1,11 0a5.5,5.5 0,1 1,-11 0"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
|
||||
@ -8,23 +8,23 @@
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
android:strokeColor="#FFEB3B"/>
|
||||
<path
|
||||
android:pathData="M18,28H8C6.895,28 6,28.895 6,30V40C6,41.105 6.895,42 8,42H18C19.105,42 20,41.105 20,40V30C20,28.895 19.105,28 18,28Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
android:strokeColor="#FFEB3B"/>
|
||||
<path
|
||||
android:pathData="M40,6H30C28.895,6 28,6.895 28,8V18C28,19.105 28.895,20 30,20H40C41.105,20 42,19.105 42,18V8C42,6.895 41.105,6 40,6Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
android:strokeColor="#FFEB3B"/>
|
||||
<path
|
||||
android:pathData="M40,28H30C28.895,28 28,28.895 28,30V40C28,41.105 28.895,42 30,42H40C41.105,42 42,41.105 42,40V30C42,28.895 41.105,28 40,28Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
android:strokeColor="#FFEB3B"/>
|
||||
</vector>
|
||||
|
||||
20
app/src/main/res/drawable/close.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M14,14L34,34"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M14,34L34,14"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@ -8,20 +8,20 @@
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M30.85,30C28.724,30 27,32.009 27,34.486C27,38.973 31.55,43.051 34,44C36.45,43.051 41,38.973 41,34.486C41,32.009 39.276,30 37.15,30C35.848,30 34.697,30.753 34,31.906C33.303,30.753 32.152,30 30.85,30Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M30,4V14H40"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
||||
@ -8,27 +8,27 @@
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#1976D2"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M38,7L44,13L38,19"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#1976D2"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M44,23C44,29.65 38.604,35 32,35H4"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#1976D2"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M10,41L4,35L10,29"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#1976D2"
|
||||
android:strokeColor="#FFEB3B"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
||||
@ -8,19 +8,19 @@
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
android:strokeColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M19,18V30"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M29,18V30"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
||||
@ -8,11 +8,11 @@
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
android:strokeColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M20,24V17.072L26,20.536L32,24L26,27.464L20,30.928V24Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"/>
|
||||
android:strokeColor="#FFFFFF"/>
|
||||
</vector>
|
||||
|
||||
8
app/src/main/res/drawable/round_edit_text.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<!-- rounded_edittext.xml -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#EEF1FF" /> <!-- 设置背景色 -->
|
||||
<corners android:radius="8dp" /> <!-- 设置圆角半径 -->
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/blue" />
|
||||
</shape>
|
||||
@ -1,10 +1,9 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:angle="45"
|
||||
android:startColor="#4CAF50"
|
||||
android:endColor="#03A9F4"
|
||||
android:endColor="#64B5F6"
|
||||
android:startColor="#42A5F5"
|
||||
android:type="linear"
|
||||
android:useLevel="false" />
|
||||
|
||||
<corners android:radius="16sp" />
|
||||
</shape>
|
||||
9
app/src/main/res/drawable/rounded_rectangle_title.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<gradient
|
||||
android:angle="45"
|
||||
android:startColor="#FFCDD2"
|
||||
android:endColor="#F8BBD0"
|
||||
android:type="linear"
|
||||
android:useLevel="false" />
|
||||
<corners android:radius="16sp" />
|
||||
</shape>
|
||||
30
app/src/main/res/drawable/save.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M39.3,6H8.7C7.209,6 6,7.209 6,8.7V39.3C6,40.791 7.209,42 8.7,42H39.3C40.791,42 42,40.791 42,39.3V8.7C42,7.209 40.791,6 39.3,6Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M32,6V24H15V6H32Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M26,13V17"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M10.997,6H35.999"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@ -8,20 +8,20 @@
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#757575"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M32,14L26,16.969V31.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#757575"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M20.5,31.5m-5.5,0a5.5,5.5 0,1 1,11 0a5.5,5.5 0,1 1,-11 0"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#333"
|
||||
android:strokeColor="#757575"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
||||
@ -1,4 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</selector>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M18,6H8C6.895,6 6,6.895 6,8V18C6,19.105 6.895,20 8,20H18C19.105,20 20,19.105 20,18V8C20,6.895 19.105,6 18,6Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#757575"/>
|
||||
<path
|
||||
android:pathData="M18,28H8C6.895,28 6,28.895 6,30V40C6,41.105 6.895,42 8,42H18C19.105,42 20,41.105 20,40V30C20,28.895 19.105,28 18,28Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#757575"/>
|
||||
<path
|
||||
android:pathData="M40,6H30C28.895,6 28,6.895 28,8V18C28,19.105 28.895,20 30,20H40C41.105,20 42,19.105 42,18V8C42,6.895 41.105,6 40,6Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#757575"/>
|
||||
<path
|
||||
android:pathData="M40,28H30C28.895,28 28,28.895 28,30V40C28,41.105 28.895,42 30,42H40C41.105,42 42,41.105 42,40V30C42,28.895 41.105,28 40,28Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#757575"/>
|
||||
</vector>
|
||||
|
||||
@ -1,4 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</selector>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M40,23V14L31,4H10C8.895,4 8,4.895 8,6V42C8,43.105 8.895,44 10,44H22"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#757575"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M30.85,30C28.724,30 27,32.009 27,34.486C27,38.973 31.55,43.051 34,44C36.45,43.051 41,38.973 41,34.486C41,32.009 39.276,30 37.15,30C35.848,30 34.697,30.753 34,31.906C33.303,30.753 32.152,30 30.85,30Z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#757575"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M30,4V14H40"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#757575"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
||||
26
app/src/main/res/drawable/voice.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:pathData="M24,4L24,4A7,7 0,0 1,31 11L31,24A7,7 0,0 1,24 31L24,31A7,7 0,0 1,17 24L17,11A7,7 0,0 1,24 4z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"/>
|
||||
<path
|
||||
android:pathData="M9,23C9,31.284 15.716,38 24,38C32.284,38 39,31.284 39,23"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:pathData="M24,38V44"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="4"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
@ -22,7 +22,7 @@
|
||||
android:layout_marginTop="75dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_marginBottom="75dp"
|
||||
android:background="@drawable/rounded_rectangle_gradient"
|
||||
android:background="@drawable/rounded_rectangle_tab"
|
||||
app:layout_constraintBottom_toTopOf="@id/seek_bar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@ -73,8 +73,10 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="18sp"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/back"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@ -122,7 +124,7 @@
|
||||
android:id="@+id/play"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:background="@drawable/rounded_rectangle_gradient"
|
||||
android:background="@drawable/rounded_rectangle_tab"
|
||||
android:padding="10dp"
|
||||
android:src="@drawable/play"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
android:id="@+id/setting"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/setting"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
69
app/src/main/res/layout/activity_record_audio.xml
Normal file
@ -0,0 +1,69 @@
|
||||
<?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=".ui.activity.RecordAudioActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:src="@drawable/back"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/record_audio"
|
||||
android:textStyle="bold"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.airbnb.lottie.LottieAnimationView
|
||||
android:id="@+id/animation_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="75dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/time"
|
||||
app:layout_constraintTop_toTopOf="@+id/title"
|
||||
app:lottie_fileName="Animation.json"
|
||||
app:lottie_loop="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/animation_view"
|
||||
android:layout_marginTop="50dp"
|
||||
android:text="@string/_00_00_00"
|
||||
android:textColor="@color/blue"
|
||||
android:textSize="44sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/voice"
|
||||
android:layout_width="75dp"
|
||||
android:layout_height="75dp"
|
||||
android:layout_marginBottom="100dp"
|
||||
android:background="@drawable/rounded_rectangle_tab"
|
||||
android:src="@drawable/voice"
|
||||
android:padding="15dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
117
app/src/main/res/layout/activity_save_audio.xml
Normal file
@ -0,0 +1,117 @@
|
||||
<?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=".ui.activity.SaveAudioActivity">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:src="@drawable/back"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginTop="20dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="75dp"
|
||||
android:src="@mipmap/placeholder"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="@string/_00_00_00"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/image" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginStart="46dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="46dp"
|
||||
android:background="@drawable/round_edit_text"
|
||||
android:gravity="center"
|
||||
android:hint="@string/please_enter_a_name_for_your_recording"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/time" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/play"
|
||||
android:layout_width="75dp"
|
||||
android:layout_height="75dp"
|
||||
android:background="@drawable/rounded_rectangle_tab"
|
||||
android:padding="5dp"
|
||||
android:src="@drawable/play"
|
||||
app:layout_constraintBottom_toTopOf="@+id/save"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/edit_text" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/save"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_marginBottom="75dp"
|
||||
android:background="@drawable/rounded_rectangle_tab"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="5dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/save" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center"
|
||||
android:text="@string/save_audio"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout 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:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
@ -7,7 +8,7 @@
|
||||
android:padding="16dp"
|
||||
tools:context=".ui.activity.SettingActivity">
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
@ -18,19 +19,22 @@
|
||||
android:id="@+id/back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="9dp"
|
||||
android:src="@drawable/back" />
|
||||
android:layout_marginStart="16dp"
|
||||
android:src="@drawable/back"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:text="@string/setting"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -62,6 +66,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
android:textSize="16sp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
@ -9,8 +9,8 @@
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:src="@mipmap/ic_launcher"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -24,7 +24,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="@string/app_name"
|
||||
android:textSize="25sp"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:gravity="center"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
55
app/src/main/res/layout/bottom_dialog.xml
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sound_title"
|
||||
android:text="@string/app_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:textStyle="bold"
|
||||
android:textSize="18sp"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/all_option"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/sound_title"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="24dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/import_audio"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@mipmap/import_audio"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/create"
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@mipmap/record_sound"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cancel_button"
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="44dp"
|
||||
android:src="@drawable/close"
|
||||
android:layout_below="@id/all_option"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/rounded_rectangle_tab"
|
||||
android:backgroundTint="#F2F2F2"
|
||||
android:padding="12dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="32dp"/>
|
||||
</RelativeLayout>
|
||||
@ -1,14 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout 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:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.fragment.AudioFragment">
|
||||
|
||||
<!-- TODO: Update blank fragment layout -->
|
||||
<TextView
|
||||
<LinearLayout
|
||||
android:id="@+id/add"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/hello_blank_fragment" />
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="50dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:background="@drawable/rounded_rectangle_tab"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="5dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
</FrameLayout>
|
||||
<ImageView
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/add" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center"
|
||||
android:text="@string/add_audio"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/audio_background"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingExtra="8dp"
|
||||
android:text="@string/oops_looks_like_there_s_no_audio_here_yet_n_please_add_some_fun_sounds"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/add" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/add"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@ -1,9 +1,10 @@
|
||||
<?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:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="150dp"
|
||||
android:background="@drawable/rounded_rectangle_gradient"
|
||||
android:background="@drawable/rounded_rectangle_title"
|
||||
android:backgroundTint="@color/white">
|
||||
|
||||
<ImageView
|
||||
@ -32,7 +33,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="@drawable/rounded_rectangle_gradient"
|
||||
android:background="@drawable/rounded_rectangle_title"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="10dp"
|
||||
@ -41,7 +42,7 @@
|
||||
android:paddingBottom="5dp"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="18sp"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="15dp"
|
||||
android:background="@drawable/rounded_rectangle_gradient">
|
||||
android:background="@drawable/rounded_rectangle_tab">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_view"
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
BIN
app/src/main/res/mipmap-hdpi/import_audio.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-hdpi/record_sound.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 26 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 42 KiB |
@ -3,4 +3,13 @@
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
<color name="gray">#757575</color>
|
||||
<color name="blue">#505BC8</color>
|
||||
<color name="yellow">#FFEB3B</color>
|
||||
<color name="color1">#D8A7FF</color>
|
||||
<color name="color2">#A0FFFC</color>
|
||||
<color name="color3">#F0C259</color>
|
||||
<color name="color4">#A6F2F2</color>
|
||||
<color name="color5">#FF9BCE</color>
|
||||
<color name="color6">#A3E1A3</color>
|
||||
<color name="color7">#B2B6FF</color>
|
||||
</resources>
|
||||
@ -3,6 +3,15 @@
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
<string name="setting">Setting</string>
|
||||
<string name="category">Category</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="collection">Collection</string>
|
||||
<string name="version">Version</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="oops_looks_like_there_s_no_audio_here_yet_n_please_add_some_fun_sounds">Oops! Looks like there’s no audio here yet.\n 🎧 Please add some fun sounds! 🎶</string>
|
||||
<string name="record_audio">Record Audio</string>
|
||||
<string name="_00_00_00">00:00:00</string>
|
||||
<string name="please_enter_a_name_for_your_recording">Please enter a name for your recording</string>
|
||||
<string name="add_audio">Add Audio</string>
|
||||
<string name="save_audio">Save Audio</string>
|
||||
</resources>
|
||||
6
keystore.properties
Normal file
@ -0,0 +1,6 @@
|
||||
app_name=Funny Prank Sounds
|
||||
package_name=keystore.properties
|
||||
keystoreFile=app/FunnyPrankSounds.jks
|
||||
key_alias=FunnyPrankSoundskey0
|
||||
key_store_password=FunnyPrankSounds
|
||||
key_password=FunnyPrankSounds
|
||||