From a9d81f90708ad391c2ae303fd43e2135f921d5c5 Mon Sep 17 00:00:00 2001 From: d3coding Date: Fri, 19 Jul 2019 21:10:53 -0300 Subject: [PATCH] Added swipe to play/download, added number filter --- app/build.gradle | 4 +- .../gmusicapi/fragments/HomeFragment.java | 95 ++++++++++++------- .../d3coding/gmusicapi/gmusic/Database.java | 23 ++++- .../d3coding/gmusicapi/gmusic/Network.java | 7 ++ .../gmusicapi/items/MusicAdapter.java | 23 +++++ .../d3coding/gmusicapi/items/MusicSwipe.java | 88 +++++++++++++++++ app/src/main/res/drawable/ic_download.xml | 10 ++ app/src/main/res/drawable/ic_play.xml | 10 ++ app/src/main/res/layout/ad_filter.xml | 36 ++++++- app/src/main/res/values/strings.xml | 1 + build.gradle | 2 +- 11 files changed, 252 insertions(+), 47 deletions(-) create mode 100644 app/src/main/java/com/d3coding/gmusicapi/items/MusicSwipe.java create mode 100644 app/src/main/res/drawable/ic_download.xml create mode 100644 app/src/main/res/drawable/ic_play.xml diff --git a/app/build.gradle b/app/build.gradle index 6b13ee1..52d4a32 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,8 @@ android { applicationId "com.d3coding.gmusicapi" minSdkVersion 28 targetSdkVersion 28 - versionCode 28 - versionName "0.24.2" + versionCode 30 + versionName "0.25" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { diff --git a/app/src/main/java/com/d3coding/gmusicapi/fragments/HomeFragment.java b/app/src/main/java/com/d3coding/gmusicapi/fragments/HomeFragment.java index a319f2f..fed82c5 100644 --- a/app/src/main/java/com/d3coding/gmusicapi/fragments/HomeFragment.java +++ b/app/src/main/java/com/d3coding/gmusicapi/fragments/HomeFragment.java @@ -15,6 +15,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.LayoutAnimationController; import android.widget.ArrayAdapter; +import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Spinner; @@ -28,6 +29,7 @@ import androidx.fragment.app.Fragment; import androidx.palette.graphics.Palette; import androidx.recyclerview.widget.DefaultItemAnimator; +import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -37,6 +39,7 @@ import com.d3coding.gmusicapi.gmusic.Download; import com.d3coding.gmusicapi.items.MusicAdapter; import com.d3coding.gmusicapi.items.MusicItem; +import com.d3coding.gmusicapi.items.MusicSwipe; import java.io.File; import java.util.ArrayList; @@ -52,6 +55,7 @@ public class HomeFragment extends Fragment { private int sort = 0; private int sortOnline = 0; + private boolean desc = false; private String filterText = ""; @@ -80,11 +84,24 @@ public void onViewCreated(@NonNull View layoutView, @Nullable Bundle savedInstan mDownload = new Download(getContext()); mAdapter = new MusicAdapter(ConvertList); + mAdapter.setOnDownloadItem((UUID) -> { + if (mDownload.scan(UUID)) + Toast.makeText(getContext(), "Music already downloaded", Toast.LENGTH_SHORT).show(); + else + downloadQueueService.execute(() -> mDownload.getQueue(UUID)); + }); + + mAdapter.setOnPlayItem((UUID) -> { + if (!openFile(UUID)) + Toast.makeText(getContext(), "Music isn't downloaded", Toast.LENGTH_SHORT).show(); + }); + LayoutAnimationController animation = AnimationUtils.loadLayoutAnimation(getContext(), R.anim.layout_animation_fall_down); recyclerView.setLayoutAnimation(animation); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(mAdapter); + (new ItemTouchHelper(new MusicSwipe(mAdapter, getContext()))).attachToRecyclerView(recyclerView); if (mOnScrollListener != null) recyclerView.addOnScrollListener(mOnScrollListener); @@ -200,21 +217,8 @@ public void onViewCreated(@NonNull View layoutView, @Nullable Bundle savedInstan builder.setOnCancelListener((dialog) -> exec.shutdown()); } - - vView.findViewById(R.id.opt_bt_play).setOnClickListener((view2) -> { - Uri uri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".fileprovider", - new File(new File(Environment.getExternalStorageDirectory(), "Gmusicapi"), musicItem.getUUID() + ".mp3")); - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(uri, getContext().getContentResolver().getType(uri)) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - startActivity(intent); - - }); - - vView.findViewById(R.id.opt_bt_open).setOnClickListener((view2) -> - startActivity(new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.parse(Environment.getExternalStorageDirectory() + "/Gmusicapi/"), "resource/folder"))); - + vView.findViewById(R.id.opt_bt_play).setOnClickListener((view2) -> openFile(musicItem.getUUID())); + vView.findViewById(R.id.opt_bt_open).setOnClickListener((view2) -> openFolder()); vView.findViewById(R.id.opt_bt_delete).setOnClickListener((view2) -> Toast.makeText(getContext(), getString(R.string.null_description), Toast.LENGTH_SHORT).show()); builder.setView(vView).create().show(); @@ -229,6 +233,24 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c return inflater.inflate(R.layout.frag_items, container, false); } + boolean openFile(String UUID) { + if (mDownload.scan(UUID)) { + Uri uri = FileProvider.getUriForFile(getContext(), getContext().getPackageName() + ".fileprovider", + new File(new File(Environment.getExternalStorageDirectory(), "Gmusicapi"), UUID + ".mp3")); + + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(uri, getContext().getContentResolver().getType(uri)) + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + startActivity(intent); + return true; + } else + return false; + } + + void openFolder() { + startActivity(new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.parse(Environment.getExternalStorageDirectory() + "/Gmusicapi/"), "resource/folder")); + } + void initThreads() { if (downloadQueueService == null) downloadQueueService = (ThreadPoolExecutor) Executors.newFixedThreadPool(Config.SIMULTANEOUS_DOWNLOAD); @@ -246,25 +268,28 @@ public int getNumItems() { } public void showFilter() { - { - ViewGroup vView = (ViewGroup) getLayoutInflater().inflate(R.layout.ad_filter, null); - Spinner spinner_organize = vView.findViewById(R.id.filter_organize); - Spinner spinner_filter = vView.findViewById(R.id.filter_filter); - ArrayAdapter adapter_organize = ArrayAdapter.createFromResource(getContext(), R.array.organize_by, android.R.layout.simple_spinner_item); - ArrayAdapter adapter_filter = ArrayAdapter.createFromResource(getContext(), R.array.filter_by, android.R.layout.simple_spinner_item); - adapter_organize.setDropDownViewResource(R.layout.spinner_simple_text_box); - adapter_filter.setDropDownViewResource(R.layout.spinner_simple_text_box); - spinner_organize.setAdapter(adapter_organize); - spinner_filter.setAdapter(adapter_filter); - spinner_organize.setSelection(sort); - spinner_filter.setSelection(sortOnline); - new AlertDialog.Builder(getContext(), R.style.AppTheme_AlertDialog).setPositiveButton(R.string.act_icon_filter, (dialog, which) -> { - sort = spinner_organize.getSelectedItemPosition(); - sortOnline = spinner_filter.getSelectedItemPosition(); - updateList(); - }).setView(vView).create().show(); - - } + + ViewGroup vView = (ViewGroup) getLayoutInflater().inflate(R.layout.ad_filter, null); + Spinner spinner_organize = vView.findViewById(R.id.filter_organize); + Spinner spinner_filter = vView.findViewById(R.id.filter_filter); + ArrayAdapter adapter_organize = ArrayAdapter.createFromResource(getContext(), R.array.organize_by, android.R.layout.simple_spinner_item); + ArrayAdapter adapter_filter = ArrayAdapter.createFromResource(getContext(), R.array.filter_by, android.R.layout.simple_spinner_item); + adapter_organize.setDropDownViewResource(R.layout.spinner_simple_text_box); + adapter_filter.setDropDownViewResource(R.layout.spinner_simple_text_box); + spinner_organize.setAdapter(adapter_organize); + spinner_filter.setAdapter(adapter_filter); + spinner_organize.setSelection(sort); + spinner_filter.setSelection(sortOnline); + + CheckBox checkBox = vView.findViewById(R.id.checkbox_ascend); + checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> desc = isChecked); + + new AlertDialog.Builder(getContext(), R.style.AppTheme_AlertDialog).setPositiveButton(R.string.act_icon_filter, (dialog, which) -> { + sort = spinner_organize.getSelectedItemPosition(); + sortOnline = spinner_filter.getSelectedItemPosition(); + updateList(); + }).setView(vView).create().show(); + } @@ -279,7 +304,7 @@ void updateList() { db = new Database(getContext()); ConvertList.clear(); - ConvertList.addAll(db.getMusicItems(sort, sortOnline, filterText, false)); + ConvertList.addAll(db.getMusicItems(sort, sortOnline, filterText, desc)); mAdapter.notifyDataSetChanged(); recyclerView.startLayoutAnimation(); diff --git a/app/src/main/java/com/d3coding/gmusicapi/gmusic/Database.java b/app/src/main/java/com/d3coding/gmusicapi/gmusic/Database.java index 305927b..765a2e2 100644 --- a/app/src/main/java/com/d3coding/gmusicapi/gmusic/Database.java +++ b/app/src/main/java/com/d3coding/gmusicapi/gmusic/Database.java @@ -21,7 +21,7 @@ public class Database extends SQLiteOpenHelper { downloadsColumn.id.name() + " INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + downloadsColumn.uuid.name() + " TEXT NOT NULL, " + downloadsColumn.downloadTimestamp.name() + " INTEGER );"; - private static final int DATABASE_VERSION = 6; + private static final int DATABASE_VERSION = 7; private static final String TYPE_TEXT = " TEXT, "; private static final String TYPE_INTEGER = " INTEGER, "; private static final String SQL_CREATE_TABLE_TRACKS = "CREATE TABLE " + TABLE_TRACKS + " ( " + @@ -41,6 +41,7 @@ public class Database extends SQLiteOpenHelper { column.albumId.name() + TYPE_TEXT + column.artistId.name() + TYPE_TEXT + column.comment.name() + TYPE_TEXT + + column.creationTimestamp.name() + TYPE_TEXT + column.totalTrackCount.name() + " INTEGER );"; private static final String SQL_DELETE_POSTS = "DROP TABLE IF EXISTS "; @@ -80,6 +81,7 @@ public void insertByTrackMetadata(List trackMetadata) { values.put(column.artistId.name(), track.artistId); values.put(column.comment.name(), track.comment); values.put(column.totalTrackCount.name(), track.totalTrackCount); + values.put(column.creationTimestamp.name(), track.creationTimestamp); db.insert(TABLE_TRACKS, null, values); } @@ -159,6 +161,8 @@ public List getMusicItems(int order, int sortOnline, String filterTit StringBuilder selection = new StringBuilder(); + int num = 5000; + if (!filterTitle.equals("")) { if (filterTitle.startsWith("AR:")) selection.append(column.artist.name()).append(" LIKE \'%").append(filterTitle.replace("AR:", "")).append("%\'"); @@ -166,7 +170,14 @@ else if (filterTitle.startsWith("AL:")) selection.append(column.album.name()).append(" LIKE \'%").append(filterTitle.replace("AL:", "")).append("%\'"); else if (filterTitle.startsWith("GE:")) selection.append(column.genre.name()).append(" LIKE \'%").append(filterTitle.replace("GE:", "")).append("%\'"); - else + else if (filterTitle.startsWith("NU:")) { + if (filterTitle.length() == 5) + try { + num = Integer.parseInt(String.valueOf(filterTitle.charAt(3)) + filterTitle.charAt(4)); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } else selection.append(column.title.name()).append(" LIKE \'%").append(filterTitle).append("%\'"); } @@ -180,13 +191,15 @@ else if (filterTitle.startsWith("GE:")) selection.append(column.uuid.name()).append(" NOT IN (SELECT ").append(downloadsColumn.uuid.name()).append(" FROM ").append(TABLE_DOWNLOAD).append(")"); } - String orderBy = null; + String orderBy; if (order == 1) orderBy = column.artist.name(); else if (order == 2) orderBy = column.album.name(); else if (order == 3) orderBy = column.genre.name(); + else if (order == 4) + orderBy = column.creationTimestamp.name(); else orderBy = column.title.name(); @@ -198,12 +211,14 @@ else if (order == 3) Cursor cursor = db.query(TABLE_TRACKS, columns, selection.toString(), null, null, null, orderBy); if (cursor != null && cursor.moveToFirst()) { + int x = 0; do { Long milliseconds = Long.parseLong(cursor.getString(4)); ret.add(new MusicItem(cursor.getString(0), cursor.getString(1), cursor.getString(2), cursor.getString(3), String.format("%02d:%02d ", TimeUnit.MILLISECONDS.toMinutes(milliseconds), TimeUnit.MILLISECONDS.toSeconds(milliseconds) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliseconds))))); - } while (cursor.moveToNext()); + ++x; + } while (cursor.moveToNext() && x < num); } try { diff --git a/app/src/main/java/com/d3coding/gmusicapi/gmusic/Network.java b/app/src/main/java/com/d3coding/gmusicapi/gmusic/Network.java index 5cc50b8..080749e 100644 --- a/app/src/main/java/com/d3coding/gmusicapi/gmusic/Network.java +++ b/app/src/main/java/com/d3coding/gmusicapi/gmusic/Network.java @@ -112,6 +112,13 @@ protected Void doInBackground(String... strings) { else trackMetadata.totalTrackCount = 0; + //Timestamp + Optional optionalCreationTimestamp = track.getCreationTimestamp(); + if (optionalComment.isPresent()) + trackMetadata.creationTimestamp = optionalCreationTimestamp.get(); + else + trackMetadata.creationTimestamp = ""; + chunkList.add(trackMetadata); } diff --git a/app/src/main/java/com/d3coding/gmusicapi/items/MusicAdapter.java b/app/src/main/java/com/d3coding/gmusicapi/items/MusicAdapter.java index a738fb3..6e6180a 100644 --- a/app/src/main/java/com/d3coding/gmusicapi/items/MusicAdapter.java +++ b/app/src/main/java/com/d3coding/gmusicapi/items/MusicAdapter.java @@ -24,6 +24,8 @@ public class MusicAdapter extends RecyclerView.Adapter value) { this.convertList = value; @@ -44,6 +46,23 @@ public void setOnItemLongClickListener(OnItemLongClickListener listener) { this.longListener = listener; } + public void setOnDownloadItem(OnDownloadItemListener mOnDownloadItem) { + this.downloadItem = mOnDownloadItem; + } + + public void setOnPlayItem(OnPlayItemListener mOnPlayItem) { + this.playItem = mOnPlayItem; + } + + String getItemUUID(int position) { + return convertList.get(position).getUUID(); + } + + public interface OnDownloadItemListener { + void OnDownloadItem(String UUID); + } + + @Override public void onBindViewHolder(final MyViewHolder holder, int position) { MusicItem musicItems = convertList.get(position); @@ -74,6 +93,10 @@ public int getItemCount() { return convertList.size(); } + public interface OnPlayItemListener { + void OnPlayItem(String UUID); + } + public interface OnItemClickListener { void onItemClick(View itemView, int position); } diff --git a/app/src/main/java/com/d3coding/gmusicapi/items/MusicSwipe.java b/app/src/main/java/com/d3coding/gmusicapi/items/MusicSwipe.java new file mode 100644 index 0000000..ef7db57 --- /dev/null +++ b/app/src/main/java/com/d3coding/gmusicapi/items/MusicSwipe.java @@ -0,0 +1,88 @@ +package com.d3coding.gmusicapi.items; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.RecyclerView; + +import com.d3coding.gmusicapi.R; + +public class MusicSwipe extends ItemTouchHelper.SimpleCallback { + private MusicAdapter mAdapter; + + private Drawable icon_download; + private Drawable icon_play; + private ColorDrawable background; + + public MusicSwipe(MusicAdapter adapter, Context context) { + super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); + mAdapter = adapter; + icon_play = ContextCompat.getDrawable(context, R.drawable.ic_play); + icon_download = ContextCompat.getDrawable(context, R.drawable.ic_download); + background = new ColorDrawable(Color.WHITE); + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + int position = viewHolder.getAdapterPosition(); + + if (direction == ItemTouchHelper.LEFT) + mAdapter.downloadItem.OnDownloadItem(mAdapter.getItemUUID(position)); + else if (direction == ItemTouchHelper.RIGHT) + mAdapter.playItem.OnPlayItem(mAdapter.getItemUUID(position)); + + mAdapter.notifyItemChanged(position); + } + + + @Override + public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + View itemView = viewHolder.itemView; + int backgroundCornerOffset = 20; + + if (dX > 0) { // Swiping to the right + int iconMargin = (itemView.getHeight() - icon_play.getIntrinsicHeight()) / 2; + int iconTop = itemView.getTop() + (itemView.getHeight() - icon_play.getIntrinsicHeight()) / 2; + int iconBottom = iconTop + icon_play.getIntrinsicHeight(); + + int iconRight = itemView.getLeft() + iconMargin + icon_play.getIntrinsicWidth(); + int iconLeft = itemView.getLeft() + iconMargin; + icon_play.setBounds(iconLeft, iconTop, iconRight, iconBottom); + + background.setBounds(itemView.getLeft(), itemView.getTop(), itemView.getLeft() + ((int) dX) + backgroundCornerOffset, itemView.getBottom()); + background.setColor(Color.rgb(255, 204, 51)); + background.draw(c); + icon_play.draw(c); + } else if (dX < 0) { // Swiping to the left + int iconMargin = (itemView.getHeight() - icon_download.getIntrinsicHeight()) / 2; + int iconTop = itemView.getTop() + (itemView.getHeight() - icon_download.getIntrinsicHeight()) / 2; + int iconBottom = iconTop + icon_download.getIntrinsicHeight(); + + int iconLeft = itemView.getRight() - iconMargin - icon_download.getIntrinsicWidth(); + int iconRight = itemView.getRight() - iconMargin; + icon_download.setBounds(iconLeft, iconTop, iconRight, iconBottom); + + background.setBounds(itemView.getRight() + ((int) dX) - backgroundCornerOffset, itemView.getTop(), itemView.getRight(), itemView.getBottom()); + background.setColor(Color.rgb(165, 123, 187)); + background.draw(c); + icon_download.draw(c); + } else { // view is unSwiped + background.setBounds(0, 0, 0, 0); + background.draw(c); + } + + } + + @Override + public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { + return false; + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml new file mode 100644 index 0000000..41f1ddc --- /dev/null +++ b/app/src/main/res/drawable/ic_download.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_play.xml b/app/src/main/res/drawable/ic_play.xml new file mode 100644 index 0000000..f3a05a8 --- /dev/null +++ b/app/src/main/res/drawable/ic_play.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/ad_filter.xml b/app/src/main/res/layout/ad_filter.xml index 3e12cb1..3a4a21f 100644 --- a/app/src/main/res/layout/ad_filter.xml +++ b/app/src/main/res/layout/ad_filter.xml @@ -2,7 +2,7 @@ + android:layout_height="wrap_content"> @@ -32,6 +30,7 @@ app:layout_constraintTop_toTopOf="parent" /> @@ -101,5 +98,34 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7c0401f..0844c6c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -103,6 +103,7 @@ Artist Album Genre + Date diff --git a/build.gradle b/build.gradle index 778a916..2f40d75 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0-beta05' + classpath 'com.android.tools.build:gradle:3.5.0-rc01' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files