V1.0.0(1)完成

This commit is contained in:
lihongwei 2024-12-25 14:08:46 +08:00
parent e2bf38525b
commit 618955ec4a
61 changed files with 1305 additions and 132 deletions

BIN
app/FunnyPrankSounds.jks Normal file

Binary file not shown.

View File

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

View File

@ -19,3 +19,15 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
if (type == 0 || type == 1) {
void bind(AudioData audioData, String name,int position) {
String audioDataImagePath = "";
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);

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

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

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

View File

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

View File

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