diff --git a/.idea/misc.xml b/.idea/misc.xml
index ea255e67..7bc501b2 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -43,7 +43,7 @@
-
+
diff --git a/app/src/main/java/com/cappielloantonio/play/helper/recyclerview/DotsIndicatorDecoration.java b/app/src/main/java/com/cappielloantonio/play/helper/recyclerview/DotsIndicatorDecoration.java
new file mode 100644
index 00000000..647a90ae
--- /dev/null
+++ b/app/src/main/java/com/cappielloantonio/play/helper/recyclerview/DotsIndicatorDecoration.java
@@ -0,0 +1,112 @@
+package com.cappielloantonio.play.helper.recyclerview;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.view.View;
+
+import androidx.annotation.ColorInt;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.jetbrains.annotations.NotNull;
+
+public class DotsIndicatorDecoration extends RecyclerView.ItemDecoration {
+ private static final String TAG = "DotsIndicatorDecoration";
+
+ private final int indicatorHeight;
+ private final int indicatorItemPadding;
+ private final int radius;
+
+ private final Paint inactivePaint = new Paint();
+ private final Paint activePaint = new Paint();
+
+ public DotsIndicatorDecoration(int radius, int padding, int indicatorHeight, @ColorInt int colorInactive, @ColorInt int colorActive) {
+ float strokeWidth = Resources.getSystem().getDisplayMetrics().density * 1;
+ this.radius = radius;
+
+ inactivePaint.setStrokeCap(Paint.Cap.ROUND);
+ inactivePaint.setStrokeWidth(strokeWidth);
+ inactivePaint.setStyle(Paint.Style.STROKE);
+ inactivePaint.setAntiAlias(true);
+ inactivePaint.setColor(colorInactive);
+
+ activePaint.setStrokeCap(Paint.Cap.ROUND);
+ activePaint.setStrokeWidth(strokeWidth);
+ activePaint.setStyle(Paint.Style.FILL);
+ activePaint.setAntiAlias(true);
+ activePaint.setColor(colorActive);
+
+ this.indicatorItemPadding = padding;
+ this.indicatorHeight = indicatorHeight;
+ }
+
+ @Override
+ public void onDrawOver(@NotNull Canvas c, @NotNull RecyclerView parent, @NotNull RecyclerView.State state) {
+ super.onDrawOver(c, parent, state);
+
+ if (parent.getAdapter() == null) return;
+
+ int itemCount = (int) Math.ceil((double) parent.getAdapter().getItemCount() / 5);
+
+ // center horizontally, calculate width and subtract half from center
+ float totalLength = this.radius * 2 * itemCount;
+ float paddingBetweenItems = Math.max(0, itemCount - 1) * indicatorItemPadding;
+ float indicatorTotalWidth = totalLength + paddingBetweenItems;
+ float indicatorStartX = (parent.getWidth() - indicatorTotalWidth) / 2f;
+
+ // center vertically in the allotted space
+ float indicatorPosY = parent.getHeight() - indicatorHeight - (float) indicatorItemPadding / 3;
+
+ drawInactiveDots(c, indicatorStartX, indicatorPosY, itemCount);
+
+ final int activePosition;
+
+ if (parent.getLayoutManager() instanceof GridLayoutManager) {
+ activePosition = ((GridLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();
+ } else if (parent.getLayoutManager() instanceof LinearLayoutManager) {
+ activePosition = ((LinearLayoutManager) parent.getLayoutManager()).findFirstVisibleItemPosition();
+ } else {
+ // not supported layout manager
+ return;
+ }
+
+ if (activePosition == RecyclerView.NO_POSITION) {
+ return;
+ }
+
+ // find offset of active page if the user is scrolling
+ final View activeChild = parent.getLayoutManager().findViewByPosition(activePosition);
+ if (activeChild == null) {
+ return;
+ }
+
+ drawActiveDot(c, indicatorStartX, indicatorPosY, activePosition);
+ }
+
+ private void drawInactiveDots(Canvas c, float indicatorStartX, float indicatorPosY, int itemCount) {
+ // width of item indicator including padding
+ final float itemWidth = this.radius * 2 + indicatorItemPadding;
+
+ float start = indicatorStartX + radius;
+ for (int i = 0; i < itemCount; i++) {
+ c.drawCircle(start, indicatorPosY, radius, inactivePaint);
+ start += itemWidth;
+ }
+ }
+
+ private void drawActiveDot(Canvas c, float indicatorStartX, float indicatorPosY, int highlightPosition) {
+ // width of item indicator including padding
+ final float itemWidth = this.radius * 2 + indicatorItemPadding;
+ float highlightStart = (float) Math.ceil(indicatorStartX + radius + itemWidth * highlightPosition / 5);
+ c.drawCircle(highlightStart, indicatorPosY, radius, activePaint);
+ }
+
+ @Override
+ public void getItemOffsets(@NotNull Rect outRect, @NotNull View view, @NotNull RecyclerView parent, @NotNull RecyclerView.State state) {
+ super.getItemOffsets(outRect, view, parent, state);
+ outRect.bottom = indicatorHeight;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java b/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java
index 769e1f61..f6114fdc 100644
--- a/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java
+++ b/app/src/main/java/com/cappielloantonio/play/ui/fragment/HomeFragment.java
@@ -11,6 +11,7 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
@@ -31,6 +32,7 @@ import com.cappielloantonio.play.adapter.SongHorizontalAdapter;
import com.cappielloantonio.play.adapter.YearAdapter;
import com.cappielloantonio.play.databinding.FragmentHomeBinding;
import com.cappielloantonio.play.helper.recyclerview.CustomLinearSnapHelper;
+import com.cappielloantonio.play.helper.recyclerview.DotsIndicatorDecoration;
import com.cappielloantonio.play.model.Album;
import com.cappielloantonio.play.model.Artist;
import com.cappielloantonio.play.model.Song;
@@ -358,6 +360,15 @@ public class HomeFragment extends Fragment {
SnapHelper starredTrackSnapHelper = new PagerSnapHelper();
starredTrackSnapHelper.attachToRecyclerView(bind.starredTracksRecyclerView);
+
+ bind.starredTracksRecyclerView.addItemDecoration(
+ new DotsIndicatorDecoration(
+ getResources().getDimensionPixelSize(R.dimen.radius),
+ getResources().getDimensionPixelSize(R.dimen.radius) * 4,
+ getResources().getDimensionPixelSize(R.dimen.dots_height),
+ requireContext().getResources().getColor(R.color.titleTextColor, null),
+ requireContext().getResources().getColor(R.color.titleTextColor, null))
+ );
}
private void initStarredAlbumsView() {
@@ -380,6 +391,15 @@ public class HomeFragment extends Fragment {
SnapHelper starredAlbumSnapHelper = new PagerSnapHelper();
starredAlbumSnapHelper.attachToRecyclerView(bind.starredAlbumsRecyclerView);
+
+ bind.starredAlbumsRecyclerView.addItemDecoration(
+ new DotsIndicatorDecoration(
+ getResources().getDimensionPixelSize(R.dimen.radius),
+ getResources().getDimensionPixelSize(R.dimen.radius) * 4,
+ getResources().getDimensionPixelSize(R.dimen.dots_height),
+ requireContext().getResources().getColor(R.color.titleTextColor, null),
+ requireContext().getResources().getColor(R.color.titleTextColor, null))
+ );
}
private void initStarredArtistsView() {
@@ -402,6 +422,15 @@ public class HomeFragment extends Fragment {
SnapHelper starredArtistSnapHelper = new PagerSnapHelper();
starredArtistSnapHelper.attachToRecyclerView(bind.starredArtistsRecyclerView);
+
+ bind.starredArtistsRecyclerView.addItemDecoration(
+ new DotsIndicatorDecoration(
+ getResources().getDimensionPixelSize(R.dimen.radius),
+ getResources().getDimensionPixelSize(R.dimen.radius) * 4,
+ getResources().getDimensionPixelSize(R.dimen.dots_height),
+ requireContext().getResources().getColor(R.color.titleTextColor, null),
+ requireContext().getResources().getColor(R.color.titleTextColor, null))
+ );
}
private void initRecentAddedAlbumView() {
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 158d1208..001488b0 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -11,4 +11,6 @@
128dp
+ 2dp
+ 2dp
\ No newline at end of file