Implemented proper Page Turn without relying on RecyclerView

This commit is contained in:
tom5079
2020-11-20 13:06:19 +09:00
parent 08403b7a4e
commit e062b8f9e9
21 changed files with 773 additions and 597 deletions

View File

@@ -1,7 +1,7 @@
<component name="CopyrightManager">
<settings>
<module2copyright>
<element module="Pupil" copyright="GPL" />
<element module="Project Files" copyright="GPL" />
</module2copyright>
</settings>
</component>

View File

@@ -6,10 +6,11 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="21"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="21" />
<uses-permission-sdk-23 android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission-sdk-23 android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false" />

View File

@@ -54,12 +54,6 @@ import java.io.File
class GalleryBlockAdapter(private val galleries: List<Int>) : RecyclerSwipeAdapter<RecyclerView.ViewHolder>(), 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<Int>) : 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<Int>) : 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
}

View File

@@ -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<CardView>(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<ImageView>(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<ImageView>(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<ImageView>(R.id.icon_prev)
val text = prev.findViewById<TextView>(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<ImageView>(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<ImageView>(R.id.icon_next)
val text = next.findViewById<TextView>(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<ImageView>(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 ->

View File

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

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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);
}
}

View File

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

View File

@@ -1,3 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
<path android:fillColor="#FF000000" android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
</vector>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="24.0" android:viewportHeight="24.0">
<group android:pivotX="12" android:scaleX="-1">
<path android:fillColor="#FF000000" android:pathData="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
</group>
</vector>

View File

@@ -17,36 +17,18 @@
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
<xyz.quaver.pupil.ui.view.MainView
android:id="@+id/main_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/main_appbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:visibility="invisible"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent">
<View
android:layout_width="match_parent"
android:layout_height="64dp"
android:visibility="invisible"
android:background="@android:color/transparent"
app:layout_scrollFlags="scroll|enterAlways"
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
</com.google.android.material.appbar.AppBarLayout>
<com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -70,63 +52,62 @@
</com.qtalk.recyclerviewfastscroller.RecyclerViewFastScroller>
<androidx.core.widget.ContentLoadingProgressBar
style="?android:attr/progressBarStyle"
android:id="@+id/main_progressbar"
</xyz.quaver.pupil.ui.view.MainView>
<androidx.core.widget.ContentLoadingProgressBar
style="?android:attr/progressBarStyle"
android:id="@+id/main_progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"/>
<TextView
android:id="@+id/main_noresult"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/main_no_result"
android:linksClickable="true"
android:visibility="invisible"/>
<com.github.clans.fab.FloatingActionMenu
android:id="@+id/main_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
app:menu_colorNormal="@color/colorAccent">
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="true"/>
app:fab_label="@string/main_fab_cancel"
app:fab_size="mini"/>
<TextView
android:id="@+id/main_noresult"
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_jump"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="@string/main_no_result"
android:linksClickable="true"
android:visibility="invisible"/>
app:fab_label="@string/main_jump_title"
app:fab_size="mini"/>
<com.github.clans.fab.FloatingActionMenu
android:id="@+id/main_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
app:menu_colorNormal="@color/colorAccent">
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_random"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_label="@string/main_fab_random"
app:fab_size="mini"/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_label="@string/main_fab_cancel"
app:fab_size="mini"/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_label="@string/main_open_gallery_by_id"
app:fab_size="mini"/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_jump"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_label="@string/main_jump_title"
app:fab_size="mini"/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_random"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_label="@string/main_fab_random"
app:fab_size="mini"/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/main_fab_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fab_label="@string/main_open_gallery_by_id"
app:fab_size="mini"/>
</com.github.clans.fab.FloatingActionMenu>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</com.github.clans.fab.FloatingActionMenu>
<xyz.quaver.pupil.ui.view.FloatingSearchView
android:id="@+id/main_searchview"
@@ -141,7 +122,6 @@
app:leftActionMode="showHamburger"
app:menu="@menu/main"
app:dismissOnOutsideTouch="true"
app:close_search_on_keyboard_dismiss="false"
tools:ignore="NewApi" />
app:close_search_on_keyboard_dismiss="false" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -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">
<com.github.piasy.biv.view.BigImageView
android:id="@+id/galleryblock_thumbnail"
android:layout_width="150dp"
android:layout_height="0dp"
android:contentDescription="@string/galleryblock_thumbnail_description"
android:adjustViewBounds="true"
android:clickable="false"
app:layout_constraintHeight_default="spread"
app:layout_constraintHeight_min="200dp"
app:layout_constraintLeft_toLeftOf="@id/progressbar"
app:layout_constraintTop_toBottomOf="@id/progressbar"
app:layout_constraintBottom_toTopOf="@id/barrier"/>
<TextView
style="@style/TextAppearance.AppCompat.Headline"
android:id="@+id/galleryblock_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/progressbar" />
<TextView
style="@style/TextAppearance.AppCompat.Medium"
android:id="@+id/galleryblock_artist"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/galleryblock_title" />
<TextView
android:id="@+id/galleryblock_series"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_artist"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="@+id/galleryblock_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_series"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
<TextView
android:id="@+id/galleryblock_language"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_type"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
<xyz.quaver.pupil.ui.view.TagChipGroup
android:id="@+id/galleryblock_tag_group"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:chipSpacing="4dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_language"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"/>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="galleryblock_thumbnail, galleryblock_tag_group"/>
<View
android:id="@+id/divider"
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"
app:layout_constraintTop_toBottomOf="@id/barrier"
android:layout_margin="8dp"/>
android:layout_height="wrap_content">
<TextView
android:id="@+id/galleryblock_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<com.github.piasy.biv.view.BigImageView
android:id="@+id/galleryblock_thumbnail"
android:layout_width="150dp"
android:layout_height="0dp"
android:contentDescription="@string/galleryblock_thumbnail_description"
android:adjustViewBounds="true"
android:clickable="false"
app:layout_constraintHeight_default="spread"
app:layout_constraintHeight_min="200dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/barrier"/>
<TextView
android:id="@+id/galleryblock_pagecount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<TextView
style="@style/TextAppearance.AppCompat.Headline"
android:id="@+id/galleryblock_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/galleryblock_favorite"
android:contentDescription="@string/app_name"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:srcCompat="@drawable/ic_star_empty"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<TextView
style="@style/TextAppearance.AppCompat.Medium"
android:id="@+id/galleryblock_artist"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/galleryblock_title" />
<TextView
android:id="@+id/galleryblock_series"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_artist"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"/>
<TextView
android:id="@+id/galleryblock_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_series"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
<TextView
android:id="@+id/galleryblock_language"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_type"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail" />
<xyz.quaver.pupil.ui.view.TagChipGroup
android:id="@+id/galleryblock_tag_group"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:chipSpacing="4dp"
app:layout_constraintTop_toBottomOf="@id/galleryblock_language"
app:layout_constraintLeft_toRightOf="@id/galleryblock_thumbnail"
app:layout_constraintRight_toRightOf="parent"/>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="galleryblock_thumbnail, galleryblock_tag_group"/>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"
app:layout_constraintTop_toBottomOf="@id/barrier"
android:layout_margin="8dp"/>
<TextView
android:id="@+id/galleryblock_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<TextView
android:id="@+id/galleryblock_pagecount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<ImageView
android:id="@+id/galleryblock_favorite"
android:contentDescription="@string/app_name"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:srcCompat="@drawable/ic_star_empty"
app:layout_constraintTop_toBottomOf="@id/divider"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</xyz.quaver.pupil.ui.view.ProgressCard>

View File

@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Pupil, Hitomi.la viewer for Android
~ Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<ImageView
android:id="@+id/icon_next"
android:contentDescription="@string/page_indicator_placeholder"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:srcCompat="@drawable/ic_navigate_next_black_24dp"
app:tint="@color/colorAccent"
android:rotation="180"/>
<TextView
android:id="@+id/text_next"
android:layout_width="1dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>

View File

@@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Pupil, Hitomi.la viewer for Android
~ Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<ImageView
android:id="@+id/icon_prev"
android:contentDescription="@string/page_indicator_placeholder"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:srcCompat="@drawable/ic_navigate_next_black_24dp"
app:tint="@color/colorAccent"
android:rotation="180"/>
<TextView
android:id="@+id/text_prev"
android:layout_width="1dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>

View File

@@ -1,15 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="true"
app:cardCornerRadius="4dp"
android:layout_margin="8dp"
app:cardUseCompatPadding="true">
tools:parentTag="androidx.cardview.widget.CardView">
<com.daimajia.swipe.SwipeLayout
android:id="@+id/swipe_layout"
@@ -54,13 +51,14 @@
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
<LinearLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground">
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical">
<androidx.core.widget.ContentLoadingProgressBar
style="?android:attr/progressBarStyleHorizontal"
@@ -70,8 +68,8 @@
android:progress="50"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</com.daimajia.swipe.SwipeLayout>
</androidx.cardview.widget.CardView>
</merge>

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:parentTag="android.widget.FrameLayout">
<TextView
android:id="@+id/prev"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center"
android:maxLines="1"
android:ellipsize="end"
app:drawableStartCompat="@drawable/navigate_prev"
app:drawableLeftCompat="@drawable/navigate_prev"
app:drawableTint="@color/colorAccent" />
<TextView
android:id="@+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:maxLines="1"
android:ellipsize="end"
app:drawableEndCompat="@drawable/navigate_next"
app:drawableRightCompat="@drawable/navigate_next"
app:drawableTint="@color/colorAccent" />
</merge>

View File

@@ -48,7 +48,7 @@
<string name="main_jump_title">ページ移動</string>
<string name="main_jump_message">現ページ番号: %1$d\nページ数: %2$d</string>
<string name="unable_to_connect">hitomi.laに接続できません</string>
<string name="main_move">%1$dページへ移動</string>
<string name="main_move_to_page">%1$dページへ移動</string>
<string name="settings_clear_downloads">ダウンロード削除</string>
<string name="settings_clear_downloads_alert_message">ダウンロードしたギャラリーを全て削除します。\n実行しますか</string>
<string name="settings_mirror_summary">ミラーサーバからイメージをロード</string>

View File

@@ -47,7 +47,7 @@
<string name="main_jump_title">페이지 이동</string>
<string name="main_jump_message">현재 페이지: %1$d\n페이지 수: %2$d</string>
<string name="unable_to_connect">hitomi.la에 연결할 수 없습니다</string>
<string name="main_move">%1$d 페이지로 이동</string>
<string name="main_move_to_page">%1$d 페이지로 이동</string>
<string name="settings_clear_downloads">다운로드 삭제</string>
<string name="settings_clear_downloads_alert_message">다운로드 된 만화를 모두 삭제합니다.\n계속하시겠습니까?</string>
<string name="main_drawer_favorite">즐겨찾기</string>

View File

@@ -21,4 +21,11 @@
<declare-styleable name="TagChipGroup">
<attr name="maxTag" format="integer"/>
</declare-styleable>
<declare-styleable name="RippleCircleStatus">
<attr name="half" format="enum">
<enum name="top" value="1"/>
<enum name="bottom" value="-1"/>
</attr>
</declare-styleable>
</resources>

View File

@@ -4,6 +4,8 @@
<color name="colorPrimaryDark">#0093c4</color>
<color name="colorAccent">#D81B60</color>
<color name="material_light_blue_300">#4fc3f7</color>
<color name="material_light_blue_700">#0288d1</color>
<color name="material_pink_600">#d81b60</color>
<color name="material_blue_700">#1976d2</color>
<color name="material_green_a700">#00c853</color>

View File

@@ -71,7 +71,7 @@
<string name="main_fab_random">Open a random gallery</string>
<string name="main_fab_cancel">Cancel all downloads</string>
<string name="main_move">Move to page %1$d</string>
<string name="main_move_to_page">Move to page %1$d</string>
<string name="main_download">DOWNLOAD</string>
<string name="main_delete">DELETE</string>

View File

@@ -20,4 +20,4 @@ kotlin.code.style=official
android.enableJetifier=true
android.useAndroidX=true
kotlin_version=1.4.10
kotlin_version=1.4.20