diff --git a/app/build.gradle b/app/build.gradle index e3fb7a4a7..ceedf853e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,6 +46,8 @@ android { applicationId 'com.kabouzeid.gramophone' versionCode 179 versionName '1.3.5' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } signingConfigs { release { @@ -126,4 +128,11 @@ dependencies { implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5' implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3' + +// Required -- JUnit 4 framework + testImplementation 'junit:junit:4.12' + // Optional -- Robolectric environment + testImplementation 'androidx.test:core:1.0.0' + // Optional -- Mockito framework + testImplementation 'org.mockito:mockito-core:1.10.19' } diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java index a500fe68e..a02eb177f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/AddToPlaylistDialog.java @@ -40,11 +40,8 @@ public static AddToPlaylistDialog create(List songs) { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { final List playlists = PlaylistLoader.getAllPlaylists(getActivity()); - CharSequence[] playlistNames = new CharSequence[playlists.size() + 1]; - playlistNames[0] = getActivity().getResources().getString(R.string.action_new_playlist); - for (int i = 1; i < playlistNames.length; i++) { - playlistNames[i] = playlists.get(i - 1).name; - } + CharSequence[] playlistNames = getPlaylistNames(playlists); + return new MaterialDialog.Builder(getActivity()) .title(R.string.add_playlist_title) .items(playlistNames) @@ -62,4 +59,13 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { }) .build(); } + + private CharSequence[] getPlaylistNames(List playlists){ + CharSequence[] playlistNames = new CharSequence[playlists.size() + 1]; + playlistNames[0] = getActivity().getResources().getString(R.string.action_new_playlist); + for (int i = 1; i < playlistNames.length; i++) { + playlistNames[i] = playlists.get(i - 1).name; + } + return playlistNames; + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java index 46830c5e9..a1e48d4aa 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/BlacklistFolderChooserDialog.java @@ -23,47 +23,11 @@ /** * @author Aidan Follestad (afollestad), modified by Karim Abou Zeid */ -public class BlacklistFolderChooserDialog extends DialogFragment implements MaterialDialog.ListCallback { - private File parentFolder; - private File[] parentContents; - private boolean canGoUp = false; +public class BlacklistFolderChooserDialog extends ChooserDialog implements MaterialDialog.ListCallback { private FolderCallback callback; - String initialPath = Environment.getExternalStorageDirectory().getAbsolutePath(); - - private String[] getContentsArray() { - if (parentContents == null) { - if (canGoUp) { - return new String[]{".."}; - } - return new String[]{}; - } - String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)]; - if (canGoUp) { - results[0] = ".."; - } - for (int i = 0; i < parentContents.length; i++) { - results[canGoUp ? i + 1 : i] = parentContents[i].getName(); - } - return results; - } - - private File[] listFiles() { - File[] contents = parentFolder.listFiles(); - List results = new ArrayList<>(); - if (contents != null) { - for (File fi : contents) { - if (fi.isDirectory()) { - results.add(fi); - } - } - Collections.sort(results, new FolderSorter()); - return results.toArray(new File[results.size()]); - } - return null; - } public static BlacklistFolderChooserDialog create() { return new BlacklistFolderChooserDialog(); @@ -72,10 +36,8 @@ public static BlacklistFolderChooserDialog create() { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && ActivityCompat.checkSelfPermission( - getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { + if (isSDKAboveAndroidMarshmallow + && isNotGrantedPermissionToReadExternalStorage) { return new MaterialDialog.Builder(getActivity()) .title(R.string.md_error_label) .content(R.string.md_storage_perm_error) @@ -88,18 +50,20 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { if (!savedInstanceState.containsKey("current_path")) { savedInstanceState.putString("current_path", initialPath); } - parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator)); + + setParentFolder(new File(savedInstanceState.getString("current_path", File.pathSeparator))); + checkIfCanGoUp(); - parentContents = listFiles(); + setParentContents(listFiles()); MaterialDialog.Builder builder = new MaterialDialog.Builder(getActivity()) - .title(parentFolder.getAbsolutePath()) + .title(getParentFolder().getAbsolutePath()) .items((CharSequence[]) getContentsArray()) .itemsCallback(this) .autoDismiss(false) .onPositive((dialog, which) -> { dismiss(); - callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder); + callback.onFolderSelection(BlacklistFolderChooserDialog.this, getParentFolder()); }) .onNegative((materialDialog, dialogAction) -> dismiss()) .positiveText(R.string.add_action) @@ -110,37 +74,21 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { @Override public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence s) { if (canGoUp && i == 0) { - parentFolder = parentFolder.getParentFile(); - if (parentFolder.getAbsolutePath().equals("/storage/emulated")) { - parentFolder = parentFolder.getParentFile(); + setParentFolder(getParentFolder().getParentFile()); + if (getParentFolder().getAbsolutePath().equals("/storage/emulated")) { + setParentFolder(getParentFolder().getParentFile()); } checkIfCanGoUp(); } else { - parentFolder = parentContents[canGoUp ? i - 1 : i]; + setParentFolder(getParentContents()[canGoUp ? i - 1 : i]); canGoUp = true; - if (parentFolder.getAbsolutePath().equals("/storage/emulated")) { - parentFolder = Environment.getExternalStorageDirectory(); + if (getParentFolder().getAbsolutePath().equals("/storage/emulated")) { + setParentFolder(Environment.getExternalStorageDirectory()); } } reload(); } - private void checkIfCanGoUp() { - canGoUp = parentFolder.getParent() != null; - } - - private void reload() { - parentContents = listFiles(); - MaterialDialog dialog = (MaterialDialog) getDialog(); - dialog.setTitle(parentFolder.getAbsolutePath()); - dialog.setItems((CharSequence[]) getContentsArray()); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString("current_path", parentFolder.getAbsolutePath()); - } public void setCallback(FolderCallback callback) { this.callback = callback; @@ -150,11 +98,5 @@ public interface FolderCallback { void onFolderSelection(@NonNull BlacklistFolderChooserDialog dialog, @NonNull File folder); } - private static class FolderSorter implements Comparator { - @Override - public int compare(File lhs, File rhs) { - return lhs.getName().compareTo(rhs.getName()); - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java index 617d7705d..3bc763971 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChangelogDialog.java @@ -10,7 +10,6 @@ import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; -import android.util.Log; import android.view.InflateException; import android.view.LayoutInflater; import android.view.View; @@ -61,6 +60,11 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { }) .build(); + loadWebView(customView); + return dialog; + } + + private void loadWebView(View customView) { final WebView webView = customView.findViewById(R.id.web_view); try { // Load from phonograph-changelog.html in the assets folder @@ -84,7 +88,6 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { } catch (Throwable e) { webView.loadData("

Unable to load

" + e.getLocalizedMessage() + "

", "text/html", "UTF-8"); } - return dialog; } public static void setChangelogRead(@NonNull Context context) { diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChooserDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChooserDialog.java new file mode 100644 index 000000000..8f2c75164 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ChooserDialog.java @@ -0,0 +1,111 @@ +package com.kabouzeid.gramophone.dialogs; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; + +import androidx.core.app.ActivityCompat; +import androidx.fragment.app.DialogFragment; + +import com.afollestad.materialdialogs.MaterialDialog; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +public class ChooserDialog extends DialogFragment{ + String initialPath = Environment.getExternalStorageDirectory().getAbsolutePath(); + private File parentFolder; + private File[] parentContents; + + protected File getParentFolder() { + return parentFolder; + } + + protected void setParentFolder(File parentFolder) { + this.parentFolder = parentFolder; + } + + protected File[] getParentContents() { + return parentContents; + } + + protected void setParentContents(File[] parentContents) { + this.parentContents = parentContents; + } + + protected boolean isCanGoUp() { + return canGoUp; + } + + protected void setCanGoUp(boolean canGoUp) { + this.canGoUp = canGoUp; + } + + protected boolean canGoUp = false; + + protected final boolean isSDKAboveAndroidMarshmallow = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; + protected final boolean isNotGrantedPermissionToReadExternalStorage = ActivityCompat.checkSelfPermission( + getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED; + + protected String[] getContentsArray() { + if (parentContents == null) { + if (canGoUp) { + return new String[]{".."}; + } + return new String[]{}; + } + String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)]; + if (canGoUp) { + results[0] = ".."; + } + for (int i = 0; i < parentContents.length; i++) { + results[canGoUp ? i + 1 : i] = parentContents[i].getName(); + } + return results; + } + + protected File[] listFiles() { + File[] contents = parentFolder.listFiles(); + List results = new ArrayList<>(); + if (contents != null) { + for (File fi : contents) { + if (fi.isDirectory()) { + results.add(fi); + } + } + Collections.sort(results, new FolderSorter()); + return results.toArray(new File[results.size()]); + } + return null; + } + + protected void checkIfCanGoUp() { + canGoUp = parentFolder.getParent() != null; + } + + protected void reload() { + parentContents = listFiles(); + MaterialDialog dialog = (MaterialDialog) getDialog(); + dialog.setTitle(parentFolder.getAbsolutePath()); + dialog.setItems((CharSequence[]) getContentsArray()); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("current_path", parentFolder.getAbsolutePath()); + } + + protected static class FolderSorter implements Comparator { + @Override + public int compare(File lhs, File rhs) { + return lhs.getName().compareTo(rhs.getName()); + } + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java index 8a498c193..10401c8f8 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/CreatePlaylistDialog.java @@ -62,13 +62,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { if (!name.isEmpty()) { if (!PlaylistsUtil.doesPlaylistExist(getActivity(), name)) { final long playlistId = PlaylistsUtil.createPlaylist(getActivity(), name); - if (getActivity() != null) { - //noinspection unchecked - List songs = getArguments().getParcelableArrayList(SONGS); - if (songs != null && !songs.isEmpty()) { - PlaylistsUtil.addToPlaylist(getActivity(), songs, playlistId, true); - } - } + addSongsToPlayList(playlistId); } else { Toast.makeText(getActivity(), getActivity().getResources().getString( R.string.playlist_exists, name), Toast.LENGTH_SHORT).show(); @@ -77,4 +71,14 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { }) .build(); } + + private void addSongsToPlayList(long playlistId) { + if (getActivity() != null) { + //noinspection unchecked + List songs = getArguments().getParcelableArrayList(SONGS); + if (songs != null && !songs.isEmpty()) { + PlaylistsUtil.addToPlaylist(getActivity(), songs, playlistId, true); + } + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java index 3b2e21443..f1e2d1355 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeletePlaylistDialog.java @@ -18,14 +18,34 @@ * @author Karim Abou Zeid (kabouzeid) */ public class DeletePlaylistDialog extends DialogFragment { - @NonNull public static DeletePlaylistDialog create(Playlist playlist) { - List list = new ArrayList<>(); + List list = new ArrayList(); list.add(playlist); return create(list); + + //private List updateLists = new ArrayList(); + } + + /*public class UpdateListDialog extends DeletePlaylistDialog { + private List updateLists; + }*/ + /* + public List getSong() { + return list; } + public void addUpdate(UpdateList updateList) { + updateLists.add(updateList); + } + public void addSong(Playlist playlist) + { + list.add(playlist); + for (UpdateList updateList: updateLists ) + updateList.update(); + }*/ + + @NonNull public static DeletePlaylistDialog create(List playlists) { DeletePlaylistDialog dialog = new DeletePlaylistDialog(); @@ -43,11 +63,10 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { int title; CharSequence content; //noinspection ConstantConditions + title = R.string.delete_playlists_title; if (playlists.size() > 1) { - title = R.string.delete_playlists_title; content = Html.fromHtml(getString(R.string.delete_x_playlists, playlists.size())); } else { - title = R.string.delete_playlist_title; content = Html.fromHtml(getString(R.string.delete_playlist_x, playlists.get(0).name)); } return new MaterialDialog.Builder(getActivity()) diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java index 1dc2f482f..08c02a017 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DeleteSongsDialog.java @@ -42,11 +42,12 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { final List songs = getArguments().getParcelableArrayList("songs"); int title; CharSequence content; + title = R.string.delete_songs_title; if (songs.size() > 1) { - title = R.string.delete_songs_title; + content = Html.fromHtml(getString(R.string.delete_x_songs, songs.size())); } else { - title = R.string.delete_song_title; + content = Html.fromHtml(getString(R.string.delete_song_x, songs.get(0).title)); } return new MaterialDialog.Builder(getActivity()) diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DialogFactory.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DialogFactory.java new file mode 100644 index 000000000..a8b50f47b --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DialogFactory.java @@ -0,0 +1,34 @@ +package com.kabouzeid.gramophone.dialogs; + +import android.util.Pair; + +import androidx.fragment.app.DialogFragment; + +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.helper.MusicPlayerRemote; +import com.kabouzeid.gramophone.model.Song; +import com.kabouzeid.gramophone.util.CalendarUtil; + +public class DialogFactory { + private static DialogFactory dialogFactory; + + public static DialogFactory getInstance(){ + if(dialogFactory == null) dialogFactory = new DialogFactory(); + return dialogFactory; + } + + public Pair getDialogInstanceAndTag(int itemId, Song song){ + switch (itemId){ + case R.id.action_sleep_timer: + return Pair.create(new SleepTimerDialog(),"SET_SLEEP_TIMER"); + case R.id.action_share: + return Pair.create(SongShareDialog.create(song),"SHARE_SONG"); + case R.id.action_add_to_playlist: + return Pair.create(AddToPlaylistDialog.create(song),"ADD_PLAYLIST"); + case R.id.action_save_playing_queue: + return Pair.create(CreatePlaylistDialog.create(MusicPlayerRemote.getPlayingQueue()),"ADD_TO_PLAYLIST"); + default: + return Pair.create(SongDetailDialog.create(song),"SONG_DETAIL"); + } + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java index 89e796e80..a7a971bc4 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/DonationsDialog.java @@ -50,6 +50,8 @@ public class DonationsDialog extends DialogFragment implements BillingProcessor. private AsyncTask skuDetailsLoadAsyncTask; + private SkuDetailed LoadSkuDetails; + public static DonationsDialog create() { return new DonationsDialog(); } @@ -84,13 +86,13 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { @Override public void onProductPurchased(@NonNull String productId, TransactionDetails details) { - loadSkuDetails(); + LoadSkuDetails.loadSkuDetails(); Toast.makeText(getContext(), R.string.thank_you, Toast.LENGTH_SHORT).show(); } @Override public void onPurchaseHistoryRestored() { - loadSkuDetails(); + LoadSkuDetails.loadSkuDetails(); } @Override @@ -100,9 +102,15 @@ public void onBillingError(int errorCode, Throwable error) { @Override public void onBillingInitialized() { - loadSkuDetails(); + LoadSkuDetails.loadSkuDetails(); } + + public void setLoadSkuDetails(SkuDetailed LoadSkuDetails) { + this.LoadSkuDetails = LoadSkuDetails; + } + + @Override public void onDestroy() { if (billingProcessor != null) { @@ -190,26 +198,26 @@ public View getView(final int position, View convertView, @NonNull ViewGroup par } SkuDetails skuDetails = getItem(position); - ViewHolder viewHolder = new ViewHolder(convertView); + DonationsDialogViewHolder donationsDialogViewHolder = new DonationsDialogViewHolder(convertView); - viewHolder.title.setText(skuDetails.title.replace("(Phonograph Music Player)", "").trim()); - viewHolder.text.setText(skuDetails.description); - viewHolder.price.setText(skuDetails.priceText); + donationsDialogViewHolder.title.setText(skuDetails.title.replace("(Phonograph Music Player)", "").trim()); + donationsDialogViewHolder.text.setText(skuDetails.description); + donationsDialogViewHolder.price.setText(skuDetails.priceText); final boolean purchased = donationsDialog.billingProcessor.isPurchased(skuDetails.productId); int titleTextColor = purchased ? ATHUtil.resolveColor(getContext(), android.R.attr.textColorHint) : ThemeStore.textColorPrimary(getContext()); int contentTextColor = purchased ? titleTextColor : ThemeStore.textColorSecondary(getContext()); //noinspection ResourceAsColor - viewHolder.title.setTextColor(titleTextColor); + donationsDialogViewHolder.title.setTextColor(titleTextColor); //noinspection ResourceAsColor - viewHolder.text.setTextColor(contentTextColor); + donationsDialogViewHolder.text.setTextColor(contentTextColor); //noinspection ResourceAsColor - viewHolder.price.setTextColor(titleTextColor); + donationsDialogViewHolder.price.setTextColor(titleTextColor); - strikeThrough(viewHolder.title, purchased); - strikeThrough(viewHolder.text, purchased); - strikeThrough(viewHolder.price, purchased); + strikeThrough(donationsDialogViewHolder.title, purchased); + strikeThrough(donationsDialogViewHolder.text, purchased); + strikeThrough(donationsDialogViewHolder.price, purchased); convertView.setOnTouchListener((v, event) -> purchased); @@ -222,7 +230,7 @@ private static void strikeThrough(TextView textView, boolean strikeThrough) { textView.setPaintFlags(strikeThrough ? textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG : textView.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG); } - static class ViewHolder { + static class DonationsDialogViewHolder { @BindView(R.id.title) TextView title; @BindView(R.id.text) @@ -230,7 +238,7 @@ static class ViewHolder { @BindView(R.id.price) TextView price; - public ViewHolder(View view) { + public DonationsDialogViewHolder(View view) { ButterKnife.bind(this, view); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java index 7c8060b05..a203578f2 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/RemoveFromPlaylistDialog.java @@ -26,6 +26,8 @@ public static RemoveFromPlaylistDialog create(PlaylistSong song) { return create(list); } + + @NonNull public static RemoveFromPlaylistDialog create(List songs) { RemoveFromPlaylistDialog dialog = new RemoveFromPlaylistDialog(); @@ -42,11 +44,10 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { final List songs = getArguments().getParcelableArrayList("songs"); int title; CharSequence content; + title = R.string.remove_songs_from_playlist_title; if (songs.size() > 1) { - title = R.string.remove_songs_from_playlist_title; content = Html.fromHtml(getString(R.string.remove_x_songs_from_playlist, songs.size())); } else { - title = R.string.remove_song_from_playlist_title; content = Html.fromHtml(getString(R.string.remove_song_x_from_playlist, songs.get(0).title)); } return new MaterialDialog.Builder(getActivity()) diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ScanMediaFolderChooserDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ScanMediaFolderChooserDialog.java index 09d5f7f98..577803507 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/ScanMediaFolderChooserDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/ScanMediaFolderChooserDialog.java @@ -32,12 +32,8 @@ /** * @author Aidan Follestad (afollestad), modified by Karim Abou Zeid */ -public class ScanMediaFolderChooserDialog extends DialogFragment implements MaterialDialog.ListCallback { +public class ScanMediaFolderChooserDialog extends ChooserDialog implements MaterialDialog.ListCallback { - String initialPath = PreferenceUtil.getInstance(getContext()).getStartDirectory().getAbsolutePath(); - private File parentFolder; - private File[] parentContents; - private boolean canGoUp = false; public static ScanMediaFolderChooserDialog create() { return new ScanMediaFolderChooserDialog(); @@ -52,45 +48,13 @@ private static void scanPaths(@NonNull WeakReference activityWeakRefer } } - private String[] getContentsArray() { - if (parentContents == null) { - if (canGoUp) { - return new String[]{".."}; - } - return new String[]{}; - } - String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)]; - if (canGoUp) { - results[0] = ".."; - } - for (int i = 0; i < parentContents.length; i++) { - results[canGoUp ? i + 1 : i] = parentContents[i].getName(); - } - return results; - } - private File[] listFiles() { - File[] contents = parentFolder.listFiles(); - List results = new ArrayList<>(); - if (contents != null) { - for (File fi : contents) { - if (fi.isDirectory()) { - results.add(fi); - } - } - Collections.sort(results, new FolderSorter()); - return results.toArray(new File[results.size()]); - } - return null; - } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M - && ActivityCompat.checkSelfPermission( - getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) - != PackageManager.PERMISSION_GRANTED) { + if (isSDKAboveAndroidMarshmallow + && isNotGrantedPermissionToReadExternalStorage) { return new MaterialDialog.Builder(getActivity()) .title(R.string.md_error_label) .content(R.string.md_storage_perm_error) @@ -103,12 +67,13 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { if (!savedInstanceState.containsKey("current_path")) { savedInstanceState.putString("current_path", initialPath); } - parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator)); + setParentFolder(new File(savedInstanceState.getString("current_path", File.pathSeparator))); + checkIfCanGoUp(); - parentContents = listFiles(); + setParentContents(listFiles()); MaterialDialog.Builder builder = new MaterialDialog.Builder(getActivity()) - .title(parentFolder.getAbsolutePath()) + .title(getParentFolder().getAbsolutePath()) .items((CharSequence[]) getContentsArray()) .itemsCallback(this) .autoDismiss(false) @@ -116,7 +81,7 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { final Context applicationContext = getActivity().getApplicationContext(); final WeakReference activityWeakReference = new WeakReference<>(getActivity()); dismiss(); - new FoldersFragment.ArrayListPathsAsyncTask(getActivity(), paths -> scanPaths(activityWeakReference, applicationContext, paths)).execute(new FoldersFragment.ArrayListPathsAsyncTask.LoadingInfo(parentFolder, FoldersFragment.AUDIO_FILE_FILTER)); + new FoldersFragment.ArrayListPathsAsyncTask(getActivity(), paths -> scanPaths(activityWeakReference, applicationContext, paths)).execute(new FoldersFragment.ArrayListPathsAsyncTask.LoadingInfo(getParentFolder(), FoldersFragment.AUDIO_FILE_FILTER)); }) .onNegative((materialDialog, dialogAction) -> dismiss()) .positiveText(R.string.action_scan_directory) @@ -127,43 +92,19 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { @Override public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence s) { if (canGoUp && i == 0) { - parentFolder = parentFolder.getParentFile(); - if (parentFolder.getAbsolutePath().equals("/storage/emulated")) { - parentFolder = parentFolder.getParentFile(); + setParentFolder(getParentFolder().getParentFile()); + if (getParentFolder().getAbsolutePath().equals("/storage/emulated")) { + setParentFolder(getParentFolder().getParentFile()); } checkIfCanGoUp(); } else { - parentFolder = parentContents[canGoUp ? i - 1 : i]; + setParentFolder(getParentContents()[canGoUp ? i - 1 : i]); canGoUp = true; - if (parentFolder.getAbsolutePath().equals("/storage/emulated")) { - parentFolder = Environment.getExternalStorageDirectory(); + if (getParentFolder().getAbsolutePath().equals("/storage/emulated")) { + setParentFolder(Environment.getExternalStorageDirectory()); } } reload(); } - private void checkIfCanGoUp() { - canGoUp = parentFolder.getParent() != null; - } - - private void reload() { - parentContents = listFiles(); - MaterialDialog dialog = (MaterialDialog) getDialog(); - dialog.setTitle(parentFolder.getAbsolutePath()); - dialog.setItems((CharSequence[]) getContentsArray()); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putString("current_path", parentFolder.getAbsolutePath()); - } - - private static class FolderSorter implements Comparator { - - @Override - public int compare(File lhs, File rhs) { - return lhs.getName().compareTo(rhs.getName()); - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SkuDetailed.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SkuDetailed.java new file mode 100644 index 000000000..0d5203bf5 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SkuDetailed.java @@ -0,0 +1,5 @@ +package com.kabouzeid.gramophone.dialogs; + +public interface SkuDetailed { + public void loadSkuDetails(); +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SkuDetails.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SkuDetails.java new file mode 100644 index 000000000..8d2e592a7 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SkuDetails.java @@ -0,0 +1,5 @@ +package com.kabouzeid.gramophone.dialogs; + +public interface SkuDetails { + public void loadSkuDetails(); +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java index 8c953e7f1..f1eb42e11 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java @@ -71,34 +71,13 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { PreferenceUtil.getInstance(getActivity()).setSleepTimerFinishMusic(shouldFinishLastSong.isChecked()); - final int minutes = seekArcProgress; - - PendingIntent pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT); - - final long nextSleepTimerElapsedTime = SystemClock.elapsedRealtime() + minutes * 60 * 1000; - PreferenceUtil.getInstance(getActivity()).setNextSleepTimerElapsedRealtime(nextSleepTimerElapsedTime); - AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); - am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSleepTimerElapsedTime, pi); - - Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_set, minutes), Toast.LENGTH_SHORT).show(); + setSleepTimer(); }) .onNeutral((dialog, which) -> { if (getActivity() == null) { return; } - final PendingIntent previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE); - if (previous != null) { - AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); - am.cancel(previous); - previous.cancel(); - Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show(); - } - - MusicService musicService = MusicPlayerRemote.musicService; - if (musicService != null && musicService.pendingQuit) { - musicService.pendingQuit = false; - Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show(); - } + cancelSleepTimer(); }) .showListener(dialog -> { if (makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) != null) { @@ -159,6 +138,35 @@ public void onStopTrackingTouch(SeekArc seekArc) { return materialDialog; } + private void cancelSleepTimer() { + final PendingIntent previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE); + if (previous != null) { + AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); + am.cancel(previous); + previous.cancel(); + Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show(); + } + + MusicService musicService = MusicPlayerRemote.musicService; + if (musicService != null && musicService.pendingQuit) { + musicService.pendingQuit = false; + Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_canceled), Toast.LENGTH_SHORT).show(); + } + } + + private void setSleepTimer() { + final int minutes = seekArcProgress; + + PendingIntent pi = makeTimerPendingIntent(PendingIntent.FLAG_CANCEL_CURRENT); + + final long nextSleepTimerElapsedTime = SystemClock.elapsedRealtime() + minutes * 60 * 1000; + PreferenceUtil.getInstance(getActivity()).setNextSleepTimerElapsedRealtime(nextSleepTimerElapsedTime); + AlarmManager am = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); + am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextSleepTimerElapsedTime, pi); + + Toast.makeText(getActivity(), getActivity().getResources().getString(R.string.sleep_timer_set, minutes), Toast.LENGTH_SHORT).show(); + } + private void updateTimeDisplayTime() { timerDisplay.setText(seekArcProgress + " min"); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java index 8416e3a85..05aff7a18 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SongDetailDialog.java @@ -75,40 +75,51 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { final TextView bitRate = dialogView.findViewById(R.id.bitrate); final TextView samplingRate = dialogView.findViewById(R.id.sampling_rate); - fileName.setText(makeTextWithTitle(context, R.string.label_file_name, "-")); - filePath.setText(makeTextWithTitle(context, R.string.label_file_path, "-")); - fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, "-")); - fileFormat.setText(makeTextWithTitle(context, R.string.label_file_format, "-")); - trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, "-")); - bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, "-")); - samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, "-")); + initDialogView(context, fileName, filePath, fileSize, fileFormat, trackLength, bitRate, samplingRate); if (song != null) { final File songFile = new File(song.data); if (songFile.exists()) { - fileName.setText(makeTextWithTitle(context, R.string.label_file_name, songFile.getName())); - filePath.setText(makeTextWithTitle(context, R.string.label_file_path, songFile.getAbsolutePath())); - fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, getFileSizeString(songFile.length()))); - try { - AudioFile audioFile = AudioFileIO.read(songFile); - AudioHeader audioHeader = audioFile.getAudioHeader(); - - fileFormat.setText(makeTextWithTitle(context, R.string.label_file_format, audioHeader.getFormat())); - trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(audioHeader.getTrackLength() * 1000))); - bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, audioHeader.getBitRate() + " kb/s")); - samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, audioHeader.getSampleRate() + " Hz")); - } catch (@NonNull CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) { - Log.e(TAG, "error while reading the song file", e); - // fallback - trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration))); - } + setDialogViewBySongFile(context, song, fileName, filePath, fileSize, fileFormat, trackLength, bitRate, samplingRate, songFile); } else { // fallback - fileName.setText(makeTextWithTitle(context, R.string.label_file_name, song.title)); - trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration))); + setDialogViewBySong(context, song, fileName, trackLength); } } - return dialog; } + + private void setDialogViewBySong(Activity context, Song song, TextView fileName, TextView trackLength) { + fileName.setText(makeTextWithTitle(context, R.string.label_file_name, song.title)); + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration))); + } + + private void setDialogViewBySongFile(Activity context, Song song, TextView fileName, TextView filePath, TextView fileSize, TextView fileFormat, TextView trackLength, TextView bitRate, TextView samplingRate, File songFile) { + fileName.setText(makeTextWithTitle(context, R.string.label_file_name, songFile.getName())); + filePath.setText(makeTextWithTitle(context, R.string.label_file_path, songFile.getAbsolutePath())); + fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, getFileSizeString(songFile.length()))); + try { + AudioFile audioFile = AudioFileIO.read(songFile); + AudioHeader audioHeader = audioFile.getAudioHeader(); + + fileFormat.setText(makeTextWithTitle(context, R.string.label_file_format, audioHeader.getFormat())); + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(audioHeader.getTrackLength() * 1000))); + bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, audioHeader.getBitRate() + " kb/s")); + samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, audioHeader.getSampleRate() + " Hz")); + } catch (@NonNull CannotReadException | IOException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) { + Log.e(TAG, "error while reading the song file", e); + // fallback + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, MusicUtil.getReadableDurationString(song.duration))); + } + } + + private void initDialogView(Activity context, TextView fileName, TextView filePath, TextView fileSize, TextView fileFormat, TextView trackLength, TextView bitRate, TextView samplingRate) { + fileName.setText(makeTextWithTitle(context, R.string.label_file_name, "-")); + filePath.setText(makeTextWithTitle(context, R.string.label_file_path, "-")); + fileSize.setText(makeTextWithTitle(context, R.string.label_file_size, "-")); + fileFormat.setText(makeTextWithTitle(context, R.string.label_file_format, "-")); + trackLength.setText(makeTextWithTitle(context, R.string.label_track_length, "-")); + bitRate.setText(makeTextWithTitle(context, R.string.label_bit_rate, "-")); + samplingRate.setText(makeTextWithTitle(context, R.string.label_sampling_rate, "-")); + } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/AbsPlayerFragment.java b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/AbsPlayerFragment.java index 6de995d71..47fef1978 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/AbsPlayerFragment.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/fragments/player/AbsPlayerFragment.java @@ -4,12 +4,16 @@ import android.content.Intent; import androidx.annotation.Nullable; import androidx.appcompat.widget.Toolbar; +import androidx.fragment.app.DialogFragment; + +import android.util.Pair; import android.view.MenuItem; import android.view.View; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.dialogs.AddToPlaylistDialog; import com.kabouzeid.gramophone.dialogs.CreatePlaylistDialog; +import com.kabouzeid.gramophone.dialogs.DialogFactory; import com.kabouzeid.gramophone.dialogs.SleepTimerDialog; import com.kabouzeid.gramophone.dialogs.SongDetailDialog; import com.kabouzeid.gramophone.dialogs.SongShareDialog; @@ -27,6 +31,7 @@ public abstract class AbsPlayerFragment extends AbsMusicServiceFragment implemen private Callbacks callbacks; private static boolean isToolbarShown = true; + @Override public void onAttach(Context context) { super.onAttach(context); @@ -46,46 +51,44 @@ public void onDetach() { @Override public boolean onMenuItemClick(MenuItem item) { final Song song = MusicPlayerRemote.getCurrentSong(); - switch (item.getItemId()) { - case R.id.action_sleep_timer: - new SleepTimerDialog().show(getFragmentManager(), "SET_SLEEP_TIMER"); - return true; - case R.id.action_toggle_favorite: - toggleFavorite(song); - return true; - case R.id.action_share: - SongShareDialog.create(song).show(getFragmentManager(), "SHARE_SONG"); - return true; - case R.id.action_equalizer: - NavigationUtil.openEqualizer(getActivity()); - return true; - case R.id.action_add_to_playlist: - AddToPlaylistDialog.create(song).show(getFragmentManager(), "ADD_PLAYLIST"); - return true; - case R.id.action_clear_playing_queue: - MusicPlayerRemote.clearQueue(); - return true; - case R.id.action_save_playing_queue: - CreatePlaylistDialog.create(MusicPlayerRemote.getPlayingQueue()).show(getActivity().getSupportFragmentManager(), "ADD_TO_PLAYLIST"); - return true; - case R.id.action_tag_editor: - Intent intent = new Intent(getActivity(), SongTagEditorActivity.class); - intent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id); - startActivity(intent); - return true; - case R.id.action_details: - SongDetailDialog.create(song).show(getFragmentManager(), "SONG_DETAIL"); - return true; - case R.id.action_go_to_album: - NavigationUtil.goToAlbum(getActivity(), song.albumId); - return true; - case R.id.action_go_to_artist: - NavigationUtil.goToArtist(getActivity(), song.artistId); - return true; + if(isDialogMenu(item.getItemId())){ + Pair p = DialogFactory.getInstance().getDialogInstanceAndTag(item.getItemId(),song); + p.first.show(getActivity().getSupportFragmentManager(),p.second); + return true; + } + else{ + switch (item.getItemId()){ + case R.id.action_toggle_favorite: + toggleFavorite(song); + return true; + case R.id.action_equalizer: + NavigationUtil.openEqualizer(getActivity()); + return true; + case R.id.action_clear_playing_queue: + MusicPlayerRemote.clearQueue(); + return true; + case R.id.action_tag_editor: + Intent intent = new Intent(getActivity(), SongTagEditorActivity.class); + intent.putExtra(AbsTagEditorActivity.EXTRA_ID, song.id); + startActivity(intent); + return true; + case R.id.action_go_to_album: + NavigationUtil.goToAlbum(getActivity(), song.albumId); + return true; + case R.id.action_go_to_artist: + NavigationUtil.goToArtist(getActivity(), song.artistId); + return true; + } + return false; } - return false; } + private boolean isDialogMenu(int itemId){ + return (itemId == R.id.action_sleep_timer) || (itemId == R.id.action_share) || (itemId == R.id.action_add_to_playlist) || + (itemId == R.id.action_save_playing_queue) || (itemId == R.id.action_details); + } + + protected void toggleFavorite(Song song) { MusicUtil.toggleFavorite(getActivity(), song); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/CalendarUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/CalendarUtil.java index e951a2365..6ea37f82e 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/CalendarUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/CalendarUtil.java @@ -1,5 +1,6 @@ package com.kabouzeid.gramophone.util; +import java.time.LocalDateTime; import java.util.Calendar; import java.util.GregorianCalendar; @@ -12,10 +13,17 @@ public class CalendarUtil { private Calendar calendar; - public CalendarUtil() { + private static CalendarUtil calendarUtil; + + private CalendarUtil() { this.calendar = Calendar.getInstance(); } + public static CalendarUtil getInstance(){ + if(calendarUtil == null) calendarUtil = new CalendarUtil(); + return calendarUtil; + } + /** * Returns the time elapsed so far today in milliseconds. * @@ -122,8 +130,8 @@ public long getElapsedYear() { * @param month The month (1 - 12). * @return The days in that month/year. */ - private int getDaysInMonth(int year, int month) { - final Calendar monthCal = new GregorianCalendar(calendar.get(Calendar.YEAR), month, 1); + public int getDaysInMonth(int year, int month) { + final Calendar monthCal = new GregorianCalendar(year, month, 1); return monthCal.getActualMaximum(Calendar.DAY_OF_MONTH); } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java index 66e4234f4..1e0834e73 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java @@ -286,7 +286,7 @@ public final String getGenreSortOrder() { } public long getLastAddedCutoff() { - final CalendarUtil calendarUtil = new CalendarUtil(); + final CalendarUtil calendarUtil = CalendarUtil.getInstance(); long interval; switch (mPreferences.getString(LAST_ADDED_CUTOFF, "")) { diff --git a/app/src/test/java/com/kabouzeid/gramophone/util/CalendarUtilTest.java b/app/src/test/java/com/kabouzeid/gramophone/util/CalendarUtilTest.java new file mode 100644 index 000000000..cab59a692 --- /dev/null +++ b/app/src/test/java/com/kabouzeid/gramophone/util/CalendarUtilTest.java @@ -0,0 +1,44 @@ +package com.kabouzeid.gramophone.util; + +import static org.junit.Assert.*; + +import com.kabouzeid.gramophone.dialogs.DialogFactory; + +import org.junit.Assert; +import org.junit.Test; + +public class CalendarUtilTest { + + /** + * Purpose: to confirm Singleton Pattern + * Input: getInstance calendarUtil1:()->CalendarUtil, calendarUtil2:()->CalendarUtil + * Expected: + * calendarUtil1 = calendarUtil2 + */ + @Test + public void calendarUtilTestGetInstance() { + System.out.println("test start"); + CalendarUtil calendarUtil1 = CalendarUtil.getInstance(); + CalendarUtil calendarUtil2 = CalendarUtil.getInstance(); + Assert.assertEquals(calendarUtil1,calendarUtil2); + } + + + /** + * Purpose: to verify leap year + * cf. month parameter value is needed to minus 1 + * Input: getDaysInMonth (2024,1) -> days in that month/year + * getDaysInMonth (2022,1) -> days in that month/year + * Expected: + * (2024,1) = 29 + * (2022,1) = 28 + */ + @Test + public void testLeapYearGetDaysInMonth() { + int februaryDaysInLeafYear = CalendarUtil.getInstance().getDaysInMonth(2024, 1); + Assert.assertEquals(29,februaryDaysInLeafYear); + + int februaryDays = CalendarUtil.getInstance().getDaysInMonth(2022, 1); + Assert.assertEquals(28,februaryDays); + } +} \ No newline at end of file diff --git a/app/src/test/java/dialog/DialogFactoryTest.java b/app/src/test/java/dialog/DialogFactoryTest.java new file mode 100644 index 000000000..fea972197 --- /dev/null +++ b/app/src/test/java/dialog/DialogFactoryTest.java @@ -0,0 +1,23 @@ +package dialog; + +import com.kabouzeid.gramophone.dialogs.DialogFactory; + +import org.junit.Assert; +import org.junit.Test; + +public class DialogFactoryTest { + + /** + * Purpose: to confirm Singleton Pattern + * Input: getInstance dialogFactory1:()->DialogFactory, dialogFactory1:()->DialogFactory + * Expected: + * dialogFactory1 = dialogFactory2 + */ + @Test + public void testGetInstance() { + System.out.println("test start"); + DialogFactory dialogFactory1 = DialogFactory.getInstance(); + DialogFactory dialogFactory2 = DialogFactory.getInstance(); + Assert.assertEquals(dialogFactory1,dialogFactory2); + } +} \ No newline at end of file