diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
index eaa059df..c4a8f7c8 100644
--- a/.idea/copyright/profiles_settings.xml
+++ b/.idea/copyright/profiles_settings.xml
@@ -1,7 +1,7 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d96312dc..d5e1e304 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,10 +6,11 @@
-
-
+
+
+
diff --git a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
index efcfbb11..a36053fe 100644
--- a/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
+++ b/app/src/main/java/xyz/quaver/pupil/adapters/GalleryBlockAdapter.kt
@@ -54,12 +54,6 @@ import java.io.File
class GalleryBlockAdapter(private val galleries: List) : RecyclerSwipeAdapter(), SwipeAdapterInterface {
- enum class ViewType {
- NEXT,
- GALLERY,
- PREV
- }
-
var updateAll = true
var thin: Boolean = Preferences["thin"]
@@ -282,51 +276,20 @@ class GalleryBlockAdapter(private val galleries: List) : RecyclerSwipeAdapt
}
}
}
- class NextViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
- class PrevViewHolder(view: LinearLayout) : RecyclerView.ViewHolder(view)
-
- class ViewHolderFactory {
- companion object {
- fun getLayoutID(type: Int): Int {
- return when(ViewType.values()[type]) {
- ViewType.NEXT -> R.layout.item_next
- ViewType.PREV -> R.layout.item_prev
- ViewType.GALLERY -> R.layout.item_galleryblock
- }
- }
- }
- }
val onChipClickedHandler = ArrayList<((Tag) -> Unit)>()
var onDownloadClickedHandler: ((Int) -> Unit)? = null
var onDeleteClickedHandler: ((Int) -> Unit)? = null
- var showNext = false
- var showPrev = false
-
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
-
- fun getViewHolder(type: Int, view: View): RecyclerView.ViewHolder {
- return when(ViewType.values()[type]) {
- ViewType.NEXT -> NextViewHolder(view as LinearLayout)
- ViewType.PREV -> PrevViewHolder(view as LinearLayout)
- ViewType.GALLERY -> GalleryViewHolder(view as ProgressCard)
- }
- }
-
- return getViewHolder(
- viewType,
- LayoutInflater.from(parent.context).inflate(
- ViewHolderFactory.getLayoutID(viewType),
- parent,
- false
- )
+ return GalleryViewHolder(
+ LayoutInflater.from(parent.context).inflate(R.layout.item_galleryblock, parent, false)
)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is GalleryViewHolder) {
- val galleryID = galleries[position-(if (showPrev) 1 else 0)]
+ val galleryID = galleries[position]
holder.bind(galleryID)
@@ -360,18 +323,7 @@ class GalleryBlockAdapter(private val galleries: List) : RecyclerSwipeAdapt
}
}
- override fun getItemCount() =
- galleries.size +
- (if (showNext) 1 else 0) +
- (if (showPrev) 1 else 0)
-
- override fun getItemViewType(position: Int): Int {
- return when {
- showPrev && position == 0 -> ViewType.PREV
- showNext && position == galleries.size+(if (showPrev) 1 else 0) -> ViewType.NEXT
- else -> ViewType.GALLERY
- }.ordinal
- }
+ override fun getItemCount() = galleries.size
override fun getSwipeLayoutResourceId(position: Int) = R.id.swipe_layout
}
\ No newline at end of file
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
index a0d1b088..c37bec02 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt
@@ -26,18 +26,16 @@ import android.text.InputType
import android.text.util.Linkify
import android.view.KeyEvent
import android.view.MenuItem
-import android.view.MotionEvent
import android.view.View
+import android.view.animation.DecelerateInterpolator
import android.widget.EditText
-import android.widget.ImageView
-import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDelegate
import androidx.cardview.widget.CardView
import androidx.core.view.GravityCompat
+import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.RecyclerView
-import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar
import com.google.firebase.crashlytics.FirebaseCrashlytics
@@ -57,6 +55,7 @@ import xyz.quaver.pupil.services.DownloadService
import xyz.quaver.pupil.types.*
import xyz.quaver.pupil.ui.dialog.DownloadLocationDialogFragment
import xyz.quaver.pupil.ui.dialog.GalleryDialog
+import xyz.quaver.pupil.ui.view.MainView
import xyz.quaver.pupil.ui.view.ProgressCard
import xyz.quaver.pupil.util.ItemClickSupport
import xyz.quaver.pupil.util.Preferences
@@ -65,10 +64,7 @@ import xyz.quaver.pupil.util.downloader.Cache
import xyz.quaver.pupil.util.downloader.DownloadManager
import xyz.quaver.pupil.util.restore
import java.util.regex.Pattern
-import kotlin.math.abs
-import kotlin.math.ceil
-import kotlin.math.min
-import kotlin.math.roundToInt
+import kotlin.math.*
class MainActivity :
BaseActivity(),
@@ -192,22 +188,22 @@ class MainActivity :
}
private fun initView() {
- var prevP1 = 0
- main_appbar_layout.addOnOffsetChangedListener(
- AppBarLayout.OnOffsetChangedListener { _, p1 ->
- main_searchview.translationY = p1.toFloat()
- main_recyclerview.scrollBy(0, prevP1 - p1)
+ main_recyclerview.addOnScrollListener(object: RecyclerView.OnScrollListener() {
+ override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
+ // -height of the search view < translationY < 0
+ main_searchview.translationY =
+ min(
+ max(
+ main_searchview.translationY - dy,
+ -main_searchview.findViewById(R.id.search_query_section).height.toFloat()
+ ), 0F)
- with(main_fab) {
- if (prevP1 > p1)
- hideMenuButton(true)
- else if (prevP1 < p1)
- showMenuButton(true)
- }
-
- prevP1 = p1
+ if (dy > 0)
+ main_fab.hideMenuButton(true)
+ else if (dy < 0)
+ main_fab.showMenuButton(true)
}
- )
+ })
Linkify.addLinks(main_noresult, Pattern.compile(getString(R.string.https_text)), null, null, { _, _ -> getString(R.string.https) })
@@ -312,6 +308,44 @@ class MainActivity :
}
}
+ with(main_view) {
+ setOnPageTurnListener(object: MainView.OnPageTurnListener {
+ override fun onPrev(page: Int) {
+ currentPage--
+
+ // disable pageturn until the contents are loaded
+ setCurrentPage(1, false)
+
+ ViewCompat.animate(main_searchview)
+ .setDuration(100)
+ .setInterpolator(DecelerateInterpolator())
+ .translationY(0F)
+
+ cancelFetch()
+ clearGalleries()
+ fetchGalleries(query, sortMode)
+ loadBlocks()
+ }
+
+ override fun onNext(page: Int) {
+ currentPage++
+
+ // disable pageturn until the contents are loaded
+ setCurrentPage(1, false)
+
+ ViewCompat.animate(main_searchview)
+ .setDuration(100)
+ .setInterpolator(DecelerateInterpolator())
+ .translationY(0F)
+
+ cancelFetch()
+ clearGalleries()
+ fetchGalleries(query, sortMode)
+ loadBlocks()
+ }
+ })
+ }
+
setupSearchBar()
setupRecyclerView()
fetchGalleries(query, sortMode)
@@ -400,207 +434,6 @@ class MainActivity :
true
}
}
-
- var origin = 0f
- var target = -1
- val perPage = Preferences["per_page", "25"].toInt()
- setOnTouchListener { _, event ->
- when(event.action) {
- MotionEvent.ACTION_UP -> {
- origin = 0f
-
- with(main_recyclerview.adapter as GalleryBlockAdapter) {
- if(showPrev) {
- showPrev = false
-
- val prev = main_recyclerview.layoutManager?.getChildAt(0)
-
- if (prev is LinearLayout) {
- val icon = prev.findViewById(R.id.icon_prev)
- prev.layoutParams.height = 1
- icon.layoutParams.height = 1
- icon.rotation = 180f
- }
-
- prev?.requestLayout()
-
- notifyItemRemoved(0)
- }
-
- if(showNext) {
- showNext = false
-
- val next = main_recyclerview.layoutManager?.let {
- getChildAt(childCount-1)
- }
-
- if (next is LinearLayout) {
- val icon = next.findViewById(R.id.icon_next)
- next.layoutParams.height = 1
- icon.layoutParams.height = 1
- icon.rotation = 0f
- }
-
- next?.requestLayout()
-
- notifyItemRemoved(itemCount)
- }
- }
-
- if (target != -1) {
- currentPage = target
-
- runOnUiThread {
- cancelFetch()
- clearGalleries()
- loadBlocks()
- }
-
- target = -1
- }
- }
- MotionEvent.ACTION_DOWN -> origin = event.y
- MotionEvent.ACTION_MOVE -> {
- if (origin == 0f)
- origin = event.y
-
- val dist = event.y - origin
-
- when {
- !canScrollVertically(-1) -> {
- //TOP
-
- //Scrolling UP
- if (dist > 0 && currentPage != 0) {
- with(main_recyclerview.adapter as GalleryBlockAdapter) {
- if(!showPrev) {
- showPrev = true
- notifyItemInserted(0)
- }
- }
-
- val prev = main_recyclerview.layoutManager?.getChildAt(0)
-
- if (prev is LinearLayout) {
- val icon = prev.findViewById(R.id.icon_prev)
- val text = prev.findViewById(R.id.text_prev).apply {
- text = getString(R.string.main_move, currentPage)
- }
- if (dist < 360) {
- prev.layoutParams.height = (dist/2).roundToInt()
- icon.layoutParams.height = (dist/2).roundToInt()
- icon.rotation = dist+180
- text.layoutParams.width = dist.roundToInt()
-
- target = -1
- }
- else {
- prev.layoutParams.height = 180
- icon.layoutParams.height = 180
- icon.rotation = 180f
- text.layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT
-
- target = currentPage-1
- }
- }
-
- prev?.requestLayout()
-
- return@setOnTouchListener true
- } else {
- with(main_recyclerview.adapter as GalleryBlockAdapter) {
- if(showPrev) {
- showPrev = false
-
- val prev = main_recyclerview.layoutManager?.getChildAt(0)
-
- if (prev is LinearLayout) {
- val icon = prev.findViewById(R.id.icon_prev)
- prev.layoutParams.height = 1
- icon.layoutParams.height = 1
- icon.rotation = 180f
- }
-
- prev?.requestLayout()
-
- notifyItemRemoved(0)
- }
- }
- }
- }
- !canScrollVertically(1) -> {
- //BOTTOM
-
- //Scrolling DOWN
- if (dist < 0 && currentPage != ceil(totalItems.toDouble()/perPage).roundToInt()-1) {
- with(main_recyclerview.adapter as GalleryBlockAdapter) {
- if(!showNext) {
- showNext = true
- notifyItemInserted(itemCount-1)
- }
- }
-
- val next = main_recyclerview.layoutManager?.let {
- getChildAt(childCount-1)
- }
-
- val absDist = abs(dist)
-
- if (next is LinearLayout) {
- val icon = next.findViewById(R.id.icon_next)
- val text = next.findViewById(R.id.text_next).apply {
- text = getString(R.string.main_move, currentPage+2)
- }
-
- if (absDist < 360) {
- next.layoutParams.height = (absDist/2).roundToInt()
- icon.layoutParams.height = (absDist/2).roundToInt()
- icon.rotation = -absDist
- text.layoutParams.width = absDist.roundToInt()
-
- target = -1
- } else {
- next.layoutParams.height = 180
- icon.layoutParams.height = 180
- icon.rotation = 0f
- text.layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT
-
- target = currentPage+1
- }
- }
-
- next?.requestLayout()
-
- return@setOnTouchListener true
- } else {
- with(main_recyclerview.adapter as GalleryBlockAdapter) {
- if(showNext) {
- showNext = false
-
- val next = main_recyclerview.layoutManager?.let {
- getChildAt(childCount-1)
- }
-
- if (next is LinearLayout) {
- val icon = next.findViewById(R.id.icon_next)
- next.layoutParams.height = 1
- icon.layoutParams.height = 1
- icon.rotation = 180f
- }
-
- next?.requestLayout()
-
- notifyItemRemoved(itemCount)
- }
- }
- }
- }
- }
- }
- }
-
- false
- }
}
}
@@ -829,7 +662,7 @@ class MainActivity :
loadingJob?.cancel()
}
- private fun clearGalleries() {
+ private fun clearGalleries() = CoroutineScope(Dispatchers.Main).launch {
galleries.clear()
with(main_recyclerview.adapter as GalleryBlockAdapter?) {
@@ -838,7 +671,6 @@ class MainActivity :
this.notifyDataSetChanged()
}
- main_appbar_layout.setExpanded(true)
main_noresult.visibility = View.INVISIBLE
main_progressbar.show()
}
@@ -959,6 +791,10 @@ class MainActivity :
return@launch
}
+ launch(Dispatchers.Main) {
+ main_view.setCurrentPage(currentPage + 1, galleryIDs.size > (currentPage+1)*perPage)
+ }
+
galleryIDs.slice(currentPage*perPage until min(currentPage*perPage+perPage, galleryIDs.size)).chunked(5).let { chunks ->
for (chunk in chunks)
chunk.map { galleryID ->
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt b/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt
index 48af83f9..064f3d0c 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/view/FloatingSearchView.kt
@@ -22,7 +22,6 @@ import android.content.Context
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.graphics.drawable.Animatable
-import android.os.Parcelable
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
@@ -38,8 +37,6 @@ import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import xyz.quaver.floatingsearchview.FloatingSearchView
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
-import xyz.quaver.floatingsearchview.util.MenuPopupHelper
-import xyz.quaver.floatingsearchview.util.view.MenuView
import xyz.quaver.floatingsearchview.util.view.SearchInputView
import xyz.quaver.pupil.R
import xyz.quaver.pupil.favoriteTags
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/view/MainView.java b/app/src/main/java/xyz/quaver/pupil/ui/view/MainView.java
new file mode 100644
index 00000000..2c37eb83
--- /dev/null
+++ b/app/src/main/java/xyz/quaver/pupil/ui/view/MainView.java
@@ -0,0 +1,462 @@
+/*
+ * Pupil, Hitomi.la viewer for Android
+ * Copyright (C) 2020 tom5079
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package xyz.quaver.pupil.ui.view;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatDelegate;
+import androidx.appcompat.content.res.AppCompatResources;
+import androidx.core.content.ContextCompat;
+import androidx.core.view.NestedScrollingChild;
+import androidx.core.view.NestedScrollingChildHelper;
+import androidx.core.view.NestedScrollingParent;
+import androidx.core.view.NestedScrollingParentHelper;
+import androidx.core.view.ViewCompat;
+import androidx.core.widget.TextViewCompat;
+
+import xyz.quaver.pupil.R;
+
+@SuppressWarnings("NullableProblems")
+public class MainView extends ViewGroup implements NestedScrollingChild, NestedScrollingParent {
+
+ private static final int PAGE_TURN_LAYOUT_SIZE = 48;
+ private static final int PAGE_TURN_ANIM_DURATION = 500;
+ private static final int PREV_OFFSET = 64;
+ private static final int RIPPLE_GIVE = 4;
+
+ private final float adjustedPageTurnLayoutSize;
+ private final float adjustedPrevOffset;
+ private final float adjustedRippleGive;
+
+ final private NestedScrollingParentHelper mNestedScrollingParentHelper;
+ final private NestedScrollingChildHelper mNestedScrollingChildHelper;
+
+ final private Vibrator mVibrator;
+
+ private View mTarget;
+
+ private TextView mPrev;
+ private TextView mNext;
+
+ private final Paint mRipplePaint = new Paint();
+ private final Rect mRippleBound = new Rect();
+
+ private int mRippleSize = 0;
+ private final int mRippleTargetSize;
+ private final ValueAnimator mRippleAnimator = new ValueAnimator();
+
+ private int mCurrentOverScroll = 0;
+
+ private int mCurrentPage = 1;
+ private boolean mShowPrev;
+ private boolean mShowNext;
+
+ private OnPageTurnListener mOnPageTurnListener;
+
+ public MainView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public MainView(@NonNull Context context, AttributeSet attr) {
+ this(context, attr, 0);
+ }
+
+ public MainView(@NonNull Context context, AttributeSet attr, int defStyle) {
+ super(context, attr, defStyle);
+
+ setWillNotDraw(false);
+
+ DisplayMetrics metrics = getResources().getDisplayMetrics();
+
+ adjustedPageTurnLayoutSize = PAGE_TURN_LAYOUT_SIZE * metrics.density;
+ adjustedPrevOffset = PREV_OFFSET * metrics.density;
+ adjustedRippleGive = RIPPLE_GIVE * metrics.density;
+
+ mRippleTargetSize = metrics.widthPixels;
+
+ mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
+ mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
+
+ mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+
+ mRippleAnimator.addUpdateListener(animation -> {
+ mRippleSize = (int) animation.getAnimatedValue();
+ invalidate();
+ });
+ mRippleAnimator.setDuration(PAGE_TURN_ANIM_DURATION);
+
+ initPageTurnView();
+ }
+
+ public void setCurrentPage(int currentPage, boolean showNext) {
+ mCurrentPage = currentPage;
+
+ mShowPrev = currentPage > 1;
+ mShowNext = showNext;
+
+ mPrev.setText(getContext().getString(R.string.main_move_to_page, mCurrentPage-1));
+ mNext.setText(getContext().getString(R.string.main_move_to_page, mCurrentPage+1));
+ }
+
+ public void setOnPageTurnListener(OnPageTurnListener listener) {
+ mOnPageTurnListener = listener;
+ }
+
+ private void initPageTurnView() {
+ TextView prev = new TextView(getContext());
+ TextView next = new TextView(getContext());
+
+ prev.setGravity(Gravity.CENTER_VERTICAL);
+ next.setGravity(Gravity.CENTER_VERTICAL);
+
+ prev.setCompoundDrawablesWithIntrinsicBounds(R.drawable.navigate_prev, 0, 0, 0);
+ next.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.navigate_next, 0);
+
+ TextViewCompat.setCompoundDrawableTintList(prev, AppCompatResources.getColorStateList(getContext(), R.color.colorAccent));
+ TextViewCompat.setCompoundDrawableTintList(next, AppCompatResources.getColorStateList(getContext(), R.color.colorAccent));
+
+ prev.setVisibility(View.INVISIBLE);
+ next.setVisibility(View.INVISIBLE);
+
+ mPrev = prev;
+ mNext = next;
+
+ addView(mPrev);
+ addView(mNext);
+
+ setCurrentPage(1, false);
+ }
+
+ private void ensureTarget() {
+ if (mTarget == null) {
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+
+ if (!child.equals(mNext) && !child.equals(mPrev)) {
+ mTarget = child;
+ break;
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int width = getMeasuredWidth();
+ final int height = getMeasuredHeight();
+
+ if (getChildCount() == 0)
+ return;
+ if (mTarget == null)
+ ensureTarget();
+ if (mTarget == null)
+ return;
+
+ mTarget.layout(
+ getPaddingLeft(),
+ getPaddingTop(),
+ width - getPaddingRight(),
+ height - getPaddingBottom()
+ );
+
+ final int prevWidth = mPrev.getMeasuredWidth();
+ mPrev.layout(
+ width / 2 - prevWidth / 2,
+ getPaddingTop() + (int) adjustedPrevOffset,
+ width / 2 + prevWidth / 2,
+ getPaddingTop() + (int) adjustedPrevOffset + mPrev.getMeasuredHeight()
+ );
+
+ final int nextWidth = mNext.getMeasuredWidth();
+ mNext.layout(
+ width / 2 - nextWidth / 2,
+ height - getPaddingBottom() - mNext.getMeasuredHeight(),
+ width / 2 + nextWidth / 2,
+ height - getPaddingBottom()
+ );
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ if (mTarget == null)
+ ensureTarget();
+ if (mTarget == null)
+ return;
+
+ mTarget.measure(
+ MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY)
+ );
+
+ mPrev.measure(
+ MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec((int) adjustedPageTurnLayoutSize, MeasureSpec.EXACTLY)
+ );
+
+ mNext.measure(
+ MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.makeMeasureSpec((int) adjustedPageTurnLayoutSize, MeasureSpec.EXACTLY)
+ );
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mCurrentOverScroll == 0)
+ return;
+
+ if (mCurrentOverScroll > 0) {
+ mRippleBound.set(
+ getPaddingLeft(),
+ (int) (getPaddingTop() - adjustedRippleGive),
+ getMeasuredWidth() - getPaddingRight(),
+ (int) (getPaddingTop() + adjustedPrevOffset + mPrev.getMeasuredHeight() + adjustedRippleGive)
+ );
+ }
+
+ if (mCurrentOverScroll < 0) {
+ final int height = getMeasuredHeight();
+ mRippleBound.set(
+ getPaddingLeft(),
+ (int) (height - getPaddingBottom() - mNext.getMeasuredHeight() - adjustedRippleGive),
+ getMeasuredWidth() - getPaddingRight(),
+ height - getPaddingBottom()
+ );
+ }
+
+ mRipplePaint.reset();
+ mRipplePaint.setStyle(Paint.Style.FILL);
+
+ int currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
+
+ switch (currentNightMode) {
+ case Configuration.UI_MODE_NIGHT_YES:
+ mRipplePaint.setColor(ContextCompat.getColor(getContext(), R.color.material_light_blue_700));
+ break;
+ case Configuration.UI_MODE_NIGHT_NO:
+ mRipplePaint.setColor(ContextCompat.getColor(getContext(), R.color.material_light_blue_300));
+ break;
+ }
+
+ canvas.drawCircle(
+ (mRippleBound.left + mRippleBound.right) / 2F,
+ mCurrentOverScroll > 0 ? mRippleBound.bottom : mRippleBound.top,
+ mRippleSize,
+ mRipplePaint
+ );
+ }
+
+ private void onOverscroll(int overscroll) {
+ if (mTarget == null)
+ ensureTarget();
+ if (mTarget == null)
+ return;
+
+ mCurrentOverScroll = overscroll;
+
+ if (overscroll > 0) {
+ mPrev.setVisibility(View.VISIBLE);
+ mNext.setVisibility(View.INVISIBLE);
+ } else if (overscroll < 0) {
+ mPrev.setVisibility(View.INVISIBLE);
+ mNext.setVisibility(View.VISIBLE);
+ } else {
+ mPrev.setVisibility(View.INVISIBLE);
+ mNext.setVisibility(View.INVISIBLE);
+ }
+
+ if (Math.abs(overscroll) >= adjustedPageTurnLayoutSize) {
+ if (!mRippleAnimator.isStarted() && mRippleSize != mRippleTargetSize) {
+ mVibrator.vibrate(10);
+
+ mRippleAnimator.setIntValues(mRippleSize, mRippleTargetSize);
+ mRippleAnimator.start();
+ }
+ } else {
+ if (!mRippleAnimator.isStarted() && mRippleSize != 0) {
+ mRippleAnimator.setIntValues(mRippleSize, 0);
+ mRippleAnimator.start();
+ }
+ }
+
+ float clippedOverScrollTop = (overscroll > 0 ? 1 : -1) * Math.min(Math.abs(overscroll), adjustedPageTurnLayoutSize);
+ mTarget.setTranslationY(clippedOverScrollTop);
+ }
+
+ private void onOverscrollEnd(int overscroll) {
+ if (mTarget == null)
+ ensureTarget();
+ if (mTarget == null)
+ return;
+
+ mRippleAnimator.cancel();
+ mRippleAnimator.setIntValues(mRippleSize, 0);
+ mRippleAnimator.start();
+
+ mPrev.setVisibility(View.INVISIBLE);
+ mNext.setVisibility(View.INVISIBLE);
+
+ ViewCompat.animate(mTarget)
+ .setDuration(PAGE_TURN_ANIM_DURATION)
+ .setInterpolator(new DecelerateInterpolator())
+ .translationY(0);
+
+ if (Math.abs(overscroll) > adjustedPageTurnLayoutSize && mOnPageTurnListener != null) {
+ if (overscroll > 0)
+ mOnPageTurnListener.onPrev(mCurrentPage-1);
+ if (overscroll < 0)
+ mOnPageTurnListener.onNext(mCurrentPage+1);
+ }
+ }
+
+ // NestedScrollingParent
+
+ private int mTotalUnconsumed = 0;
+
+ @Override
+ public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+ return isEnabled() && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
+ }
+
+ @Override
+ public void onNestedScrollAccepted(View child, View target, int axes) {
+ mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
+ startNestedScroll(axes & ViewCompat.SCROLL_AXIS_VERTICAL);
+
+ mTotalUnconsumed = 0;
+ }
+
+ @Override
+ public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+ if (mTotalUnconsumed != 0 && dy > 0 == mTotalUnconsumed > 0) {
+ if (Math.abs(dy) > Math.abs(mTotalUnconsumed)) {
+ consumed[1] = dy - mTotalUnconsumed;
+ mTotalUnconsumed = 0;
+ } else {
+ mTotalUnconsumed -= dy;
+ consumed[1] = dy;
+ }
+
+ onOverscroll(mTotalUnconsumed);
+ }
+
+ final int[] parentConsumed = new int[2];
+ if (dispatchNestedPreScroll(dx - consumed[0], dy - consumed[1], parentConsumed, null)) {
+ consumed[0] += parentConsumed[0];
+ consumed[1] += parentConsumed[1];
+ }
+ }
+
+ @Override
+ public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
+ final int[] mParentOffsetInWindow = new int[2];
+ dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, mParentOffsetInWindow);
+
+ final int dy = dyUnconsumed + mParentOffsetInWindow[1];
+
+ if (mTotalUnconsumed == 0 && ((dy < 0 && !mShowPrev) || (dy > 0 && !mShowNext)))
+ return;
+
+ if (dy != 0) {
+ mTotalUnconsumed -= dy;
+ onOverscroll(mTotalUnconsumed);
+ }
+ }
+
+ @Override
+ public void onStopNestedScroll(View child) {
+ mNestedScrollingParentHelper.onStopNestedScroll(child);
+
+ if (Math.abs(mTotalUnconsumed) > 0) {
+ onOverscrollEnd(mTotalUnconsumed);
+ mTotalUnconsumed = 0;
+ }
+
+ stopNestedScroll();
+ }
+
+ // NestedScrollingChild
+
+ @Override
+ public void setNestedScrollingEnabled(boolean enabled) {
+ mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
+ }
+
+ @Override
+ public boolean isNestedScrollingEnabled() {
+ return mNestedScrollingChildHelper.isNestedScrollingEnabled();
+ }
+
+ @Override
+ public boolean startNestedScroll(int axes) {
+ return mNestedScrollingChildHelper.startNestedScroll(axes);
+ }
+
+ @Override
+ public void stopNestedScroll() {
+ mNestedScrollingChildHelper.stopNestedScroll();
+ }
+
+ @Override
+ public boolean hasNestedScrollingParent() {
+ return mNestedScrollingChildHelper.hasNestedScrollingParent();
+ }
+
+ @Override
+ public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
+ return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow) {
+ return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
+ }
+
+ @Override
+ public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
+ return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
+ }
+
+ @Override
+ public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
+ return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
+ }
+
+ public interface OnPageTurnListener {
+ void onPrev(int page);
+ void onNext(int page);
+ }
+}
diff --git a/app/src/main/java/xyz/quaver/pupil/ui/view/ProgressCard.kt b/app/src/main/java/xyz/quaver/pupil/ui/view/ProgressCard.kt
index d8c77ff4..c66bbda1 100644
--- a/app/src/main/java/xyz/quaver/pupil/ui/view/ProgressCard.kt
+++ b/app/src/main/java/xyz/quaver/pupil/ui/view/ProgressCard.kt
@@ -4,13 +4,14 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
+import androidx.cardview.widget.CardView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import kotlinx.android.synthetic.main.view_progress_card.view.*
import xyz.quaver.pupil.R
-class ProgressCard @JvmOverloads constructor(context: Context, attr: AttributeSet? = null, defStyle: Int = R.attr.cardViewStyle) : ConstraintLayout(context, attr, defStyle) {
+class ProgressCard @JvmOverloads constructor(context: Context, attr: AttributeSet? = null, defStyle: Int = R.attr.cardViewStyle) : CardView(context, attr, defStyle) {
enum class Type {
LOADING,
@@ -61,10 +62,11 @@ class ProgressCard @JvmOverloads constructor(context: Context, attr: AttributeSe
}
}
- override fun addView(child: View?, params: ViewGroup.LayoutParams?) =
+ override fun addView(child: View?, index: Int, params: ViewGroup.LayoutParams?) {
if (childCount == 0)
- super.addView(child, params)
+ super.addView(child, index, params)
else
- content.addView(child, params)
+ content.addView(child, index, params)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml b/app/src/main/res/drawable/navigate_next.xml
similarity index 77%
rename from app/src/main/res/drawable/ic_navigate_next_black_24dp.xml
rename to app/src/main/res/drawable/navigate_next.xml
index 137bcca7..c25983c7 100644
--- a/app/src/main/res/drawable/ic_navigate_next_black_24dp.xml
+++ b/app/src/main/res/drawable/navigate_next.xml
@@ -1,3 +1,3 @@
-
+
diff --git a/app/src/main/res/drawable/navigate_prev.xml b/app/src/main/res/drawable/navigate_prev.xml
new file mode 100644
index 00000000..a3081f14
--- /dev/null
+++ b/app/src/main/res/drawable/navigate_prev.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main_content.xml b/app/src/main/res/layout/activity_main_content.xml
index cbe12f09..bfa69e3e 100644
--- a/app/src/main/res/layout/activity_main_content.xml
+++ b/app/src/main/res/layout/activity_main_content.xml
@@ -17,36 +17,18 @@
~ along with this program. If not, see .
-->
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ app:fab_label="@string/main_fab_cancel"
+ app:fab_size="mini"/>
-
+ app:fab_label="@string/main_jump_title"
+ app:fab_size="mini"/>
-
+
-
+
-
-
-
-
-
-
-
-
-
+
+ app:close_search_on_keyboard_dismiss="false" />
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_galleryblock.xml b/app/src/main/res/layout/item_galleryblock.xml
index b8fc0792..7638f8e7 100644
--- a/app/src/main/res/layout/item_galleryblock.xml
+++ b/app/src/main/res/layout/item_galleryblock.xml
@@ -24,126 +24,137 @@
android:id="@+id/galleryblock_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:clipChildren="true"
+ app:cardCornerRadius="4dp"
+ android:layout_marginLeft="8dp"
+ android:layout_marginRight="8dp"
+ app:cardUseCompatPadding="true"
tools:ignore="RtlHardcoded">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="wrap_content">
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_next.xml b/app/src/main/res/layout/item_next.xml
deleted file mode 100644
index 4627e96d..00000000
--- a/app/src/main/res/layout/item_next.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_prev.xml b/app/src/main/res/layout/item_prev.xml
deleted file mode 100644
index c1051d66..00000000
--- a/app/src/main/res/layout/item_prev.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_progress_card.xml b/app/src/main/res/layout/view_progress_card.xml
index 2b7b65bb..671a789f 100644
--- a/app/src/main/res/layout/view_progress_card.xml
+++ b/app/src/main/res/layout/view_progress_card.xml
@@ -1,15 +1,12 @@
-
+ tools:parentTag="androidx.cardview.widget.CardView">
-
+ android:background="?android:attr/selectableItemBackground"
+ android:orientation="vertical">
-
+
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_swipe_pageturn.xml b/app/src/main/res/layout/view_swipe_pageturn.xml
new file mode 100644
index 00000000..6d1f82e2
--- /dev/null
+++ b/app/src/main/res/layout/view_swipe_pageturn.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index c351ff4f..fcce73f7 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -48,7 +48,7 @@
ページ移動
現ページ番号: %1$d\nページ数: %2$d
hitomi.laに接続できません
- %1$dページへ移動
+ %1$dページへ移動
ダウンロード削除
ダウンロードしたギャラリーを全て削除します。\n実行しますか?
ミラーサーバからイメージをロード
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index d7f74f3c..4824b0a7 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -47,7 +47,7 @@
페이지 이동
현재 페이지: %1$d\n페이지 수: %2$d
hitomi.la에 연결할 수 없습니다
- %1$d 페이지로 이동
+ %1$d 페이지로 이동
다운로드 삭제
다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?
즐겨찾기
diff --git a/app/src/main/res/values/attr.xml b/app/src/main/res/values/attrs.xml
similarity index 80%
rename from app/src/main/res/values/attr.xml
rename to app/src/main/res/values/attrs.xml
index d13a3706..753729ee 100644
--- a/app/src/main/res/values/attr.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -21,4 +21,11 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index faaf0be1..b313bcdf 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -4,6 +4,8 @@
#0093c4
#D81B60
+ #4fc3f7
+ #0288d1
#d81b60
#1976d2
#00c853
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6173bf9e..90b50039 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -71,7 +71,7 @@
Open a random gallery
Cancel all downloads
- Move to page %1$d
+ Move to page %1$d
DOWNLOAD
DELETE
diff --git a/gradle.properties b/gradle.properties
index da320022..2c2f1284 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -20,4 +20,4 @@ kotlin.code.style=official
android.enableJetifier=true
android.useAndroidX=true
-kotlin_version=1.4.10
\ No newline at end of file
+kotlin_version=1.4.20
\ No newline at end of file