Convert galleryDetail tags to compose

This commit is contained in:
tarsin committed 2023-03-16 23:19:54 +08:00
1 parent b63b189fda
commit 6ceb50c0bd
9 files changed
+85 -470

No files matched your search

@@ -23,7 +23,6 @@ import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.net.Uri
import android.os.Build
import android.os.Bundle
@@ -32,17 +31,17 @@ import android.text.Html
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.View.OnLongClickListener
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.LinearLayout
import android.widget.ListView
import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.IntDef
import androidx.annotation.StringRes
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
@@ -52,6 +51,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CloudDone
import androidx.compose.material.icons.filled.Difference
@@ -82,7 +82,6 @@ import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ConcatAdapter
import coil.Coil.imageLoader
@@ -144,7 +143,6 @@ import com.hippo.util.ReadableTime
import com.hippo.util.addTextToClipboard
import com.hippo.util.getParcelableCompat
import com.hippo.view.ViewTransition
import com.hippo.widget.AutoWrapLayout
import com.hippo.widget.ObservedTextView
import com.hippo.widget.SimpleGridAutoSpanLayout
import com.hippo.widget.recyclerview.AutoGridLayoutManager
@@ -157,12 +155,10 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withUIContext
import okhttp3.HttpUrl.Companion.toHttpUrl
import rikka.core.res.resolveColor
import kotlin.math.roundToInt
import com.hippo.ehviewer.download.DownloadManager as downloadManager
class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, DownloadInfoListener,
OnLongClickListener {
class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, DownloadInfoListener {
private var _binding: SceneGalleryDetailBinding? = null
private val binding
get() = _binding!!
@@ -683,8 +679,7 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
Column(
modifier = Modifier
.padding(horizontal = dimensionResource(id = R.dimen.keyline_margin))
.padding(top = dimensionResource(id = R.dimen.keyline_margin)),
horizontalAlignment = Alignment.CenterHorizontally
.padding(top = dimensionResource(id = R.dimen.keyline_margin))
) {
if (!composeBindingGD?.newerVersions.isNullOrEmpty()) {
Box(contentAlignment = Alignment.Center) {
@@ -745,7 +740,9 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
Spacer(modifier = Modifier.size(dimensionResource(id = R.dimen.keyline_margin)))
ElevatedCard(onClick = ::showRateDialog) {
Column(
modifier = Modifier.padding(8.dp),
modifier = Modifier
.padding(8.dp)
.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
GalleryDetailRating(rating = composeBindingGD?.rating ?: 0f)
@@ -754,6 +751,13 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
}
}
Spacer(modifier = Modifier.size(dimensionResource(id = R.dimen.keyline_margin)))
val tags = composeBindingGD?.tags
if (tags.isNullOrEmpty()) {
Text(text = stringResource(id = R.string.no_tags))
} else {
GalleryDetailTags(tags)
}
Spacer(modifier = Modifier.size(dimensionResource(id = R.dimen.keyline_margin)))
}
}
}
@@ -888,72 +892,82 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
updateFavoriteDrawable()
ratingText = getAllRatingText(gd.rating, gd.ratingCount)
torrentText = resources.getString(R.string.torrent_count, gd.torrentCount)
bindTags(gd.tags)
bindComments(gd.comments!!.comments)
bindPreviews(gd)
}
private fun bindTags(tagGroups: Array<GalleryTagGroup>?) {
context ?: return
val inflater = layoutInflater
_binding ?: return
binding.content.tags.run {
tags.removeViews(1, tags.childCount - 1)
if (tagGroups.isNullOrEmpty()) {
noTags.visibility = View.VISIBLE
return
@Composable
private fun GalleryDetailTags(tagGroups: Array<GalleryTagGroup>) {
@Composable
fun baseRoundText(
text: String,
weak: Boolean = false,
isGroup: Boolean = false,
modifier: Modifier = Modifier
) {
val bgColor = if (isGroup) {
MaterialTheme.colorScheme.primaryContainer
} else {
noTags.visibility = View.GONE
MaterialTheme.colorScheme.tertiaryContainer
}
}
tagGroups ?: return
val ehTags =
if (Settings.showTagTranslations && isTranslatable(requireContext())) EhTagDatabase else null
val colorTag = theme.resolveColor(R.attr.tagBackgroundColor)
val colorName = theme.resolveColor(R.attr.tagGroupBackgroundColor)
for (tg in tagGroups) {
val ll = inflater.inflate(
R.layout.gallery_tag_group,
binding.content.tags.tags,
false
) as LinearLayout
ll.orientation = LinearLayout.HORIZONTAL
binding.content.tags.tags.addView(ll)
var readableTagName: String? = null
if (ehTags != null && ehTags.isInitialized()) {
readableTagName = ehTags.getTranslation(tag = tg.groupName)
}
val tgName = inflater.inflate(R.layout.item_gallery_tag, ll, false) as TextView
ll.addView(tgName)
tgName.text = readableTagName ?: tg.groupName
tgName.backgroundTintList = ColorStateList.valueOf(colorName)
val prefix = namespaceToPrefix(tg.groupName!!)
val awl = AutoWrapLayout(context)
ll.addView(
awl,
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
Text(
text = text,
modifier = modifier
.background(bgColor, RoundedCornerShape(64.dp))
.padding(horizontal = 12.dp, vertical = 4.dp),
style = MaterialTheme.typography.labelLarge
)
tg.forEach {
val tag = inflater.inflate(R.layout.item_gallery_tag, awl, false) as TextView
awl.addView(tag)
val tagStr = if (it.startsWith('_')) {
val alpha = ColorUtils.setAlphaComponent(tag.currentTextColor, 128)
tag.setTextColor(alpha)
it.substring(1)
} else {
it
Spacer(modifier = Modifier.size(8.dp))
}
val canTranslate = Settings.showTagTranslations && isTranslatable(requireContext())
val ehTags = EhTagDatabase.takeIf { canTranslate }
fun String.translate(): String {
return ehTags?.takeIf { it.isInitialized() }?.getTranslation(tag = this) ?: this
}
fun String.translate(prefix: String): String {
return ehTags?.takeIf { it.isInitialized() }
?.getTranslation(prefix = prefix, tag = this) ?: this
}
tagGroups.forEach {
Row {
it.groupName?.run {
baseRoundText(
text = translate(),
isGroup = true
)
val prefix = namespaceToPrefix(this) ?: return
FlowRow {
it.forEach {
val weak = it.startsWith('_')
val real = it.removePrefix("_")
val translated = real.translate(prefix)
fun onClick() {
val lub = ListUrlBuilder()
lub.mode = ListUrlBuilder.MODE_TAG
lub.keyword = real
navigate(R.id.galleryListScene, lub.toStartArgs(), true)
}
fun onLongClick() {
showTagDialog(translated, real)
}
baseRoundText(
text = translated,
weak = weak,
modifier = Modifier.combinedClickable(
onClick = ::onClick,
onLongClick = ::onLongClick
)
)
}
}
}
var readableTag: String? = null
if (ehTags != null && ehTags.isInitialized()) {
readableTag = ehTags.getTranslation(prefix, tagStr)
}
tag.text = readableTag ?: tagStr
tag.backgroundTintList = ColorStateList.valueOf(colorTag)
tag.setTag(R.id.tag, tg.groupName + ":" + tagStr)
tag.setOnClickListener(this)
tag.setOnLongClickListener(this)
}
Spacer(modifier = Modifier.size(8.dp))
}
}
@@ -1132,17 +1146,6 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
args.putParcelable(GalleryCommentsScene.KEY_GALLERY_DETAIL, galleryDetail)
navigate(R.id.galleryCommentsScene, args)
}
else -> {
val o = v.getTag(R.id.tag)
if (o is String) {
val lub = ListUrlBuilder()
lub.mode = ListUrlBuilder.MODE_TAG
lub.keyword = o
navigate(R.id.galleryListScene, lub.toStartArgs(), true)
return
}
}
}
}
@@ -1161,7 +1164,7 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
.show()
}
private fun showTagDialog(tv: TextView, tag: String) {
private fun showTagDialog(translated: String, tag: String) {
val context = context ?: return
val temp: String
val index = tag.indexOf(':')
@@ -1175,7 +1178,7 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
val resources = context.resources
menu.add(resources.getString(android.R.string.copy))
menuId.add(R.id.copy)
if (temp != tv.text.toString()) {
if (temp != translated) {
menu.add(resources.getString(R.string.copy_trans))
menuId.add(R.id.copy_trans)
}
@@ -1217,7 +1220,7 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
}
R.id.copy_trans -> {
requireActivity().addTextToClipboard(tv.text.toString(), false)
requireActivity().addTextToClipboard(translated, false)
}
}
}.show()
@@ -1299,15 +1302,6 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
}
}
override fun onLongClick(v: View): Boolean {
val tag = v.getTag(R.id.tag) as? String
if (null != tag) {
showTagDialog(v as TextView, tag)
return true
}
return false
}
private fun updateDownloadText() {
_binding ?: return
downloadButtonText = when (mDownloadState) {
@@ -1,266 +0,0 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.hippo.ehviewer.R;
import java.util.ArrayList;
import java.util.List;
/**
* A ViewGroup that can layout views in line and auto wrap
*
* @author Hippo
*/
public class AutoWrapLayout extends ViewGroup {
private static final Alignment[] sBaseLineArray = {Alignment.TOP,
Alignment.CENTER, Alignment.BOTTOM};
private final List<Rect> rectList = new ArrayList<>();
private Alignment mAlignment;
public AutoWrapLayout(Context context) {
super(context);
}
public AutoWrapLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AutoWrapLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.AutoWrapLayout, defStyle, 0);
int index = a.getInt(R.styleable.AutoWrapLayout_alignment, -1);
if (index >= 0) {
setAlignment(sBaseLineArray[index]);
}
a.recycle();
}
public Alignment getAlignment() {
return mAlignment;
}
public void setAlignment(Alignment baseLine) {
if (baseLine == null) {
return;
}
if (mAlignment != baseLine) {
mAlignment = baseLine;
requestLayout();
invalidate();
}
}
private void adjustBaseLine(int lineHeight, int startIndex, int endIndex) {
if (mAlignment == Alignment.TOP)
return;
for (int index = startIndex; index < endIndex; index++) {
final View child = getChildAt(index);
final MarginLayoutParams lp =
(MarginLayoutParams) child.getLayoutParams();
Rect rect = rectList.get(index);
int offsetRaw = lineHeight - rect.height() - lp.topMargin - lp.bottomMargin;
if (mAlignment == Alignment.CENTER)
rect.offset(0, offsetRaw / 2);
else if (mAlignment == Alignment.BOTTOM)
rect.offset(0, offsetRaw);
}
}
/**
* each row or line at least show one child
* <p>
* horizontal only show child can show or partly show in parent
*/
@SuppressLint("DrawAllocation")
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.UNSPECIFIED)
maxWidth = Integer.MAX_VALUE;
if (heightMode == MeasureSpec.UNSPECIFIED)
maxHeight = Integer.MAX_VALUE;
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
int maxRightBound = maxWidth - paddingRight;
int maxBottomBound = maxHeight - paddingBottom;
int left;
int top;
int right;
int bottom;
int rightBound = paddingLeft;
int maxRightNoPadding = rightBound;
int bottomBound;
int lastMaxBottom = paddingTop;
int maxBottom = lastMaxBottom;
int childWidth;
int childHeight;
int lineStartIndex = 0;
int lineEndIndex; // endIndex + 1
rectList.clear();
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
final View child = getChildAt(index);
child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
if (child.getVisibility() == View.GONE)
continue;
final MarginLayoutParams lp =
(MarginLayoutParams) child.getLayoutParams();
childWidth = child.getMeasuredWidth();
childHeight = child.getMeasuredHeight();
left = rightBound + lp.leftMargin;
right = left + childWidth;
rightBound = right + lp.rightMargin;
if (rightBound > maxRightBound) { // Go to next row
lineEndIndex = index;
// Adjust child position base on baseline
adjustBaseLine(maxBottom - lastMaxBottom, lineStartIndex, lineEndIndex);
// If child can't show in parent begin this line
if (maxBottom >= maxBottomBound)
break;
// If it is first item in line, try to show it all
if (lineEndIndex == lineStartIndex) {
child.measure(MeasureSpec.makeMeasureSpec(
maxWidth - paddingLeft - paddingRight
- lp.leftMargin - lp.rightMargin, MeasureSpec.AT_MOST),
MeasureSpec.UNSPECIFIED);
childWidth = child.getMeasuredWidth();
childHeight = child.getMeasuredHeight();
}
left = paddingLeft + lp.leftMargin;
right = left + childWidth;
rightBound = right + lp.rightMargin;
lastMaxBottom = maxBottom;
top = lastMaxBottom + lp.topMargin;
bottom = top + childHeight;
bottomBound = bottom + lp.bottomMargin;
lineStartIndex = index;
} else {
top = lastMaxBottom + lp.topMargin;
bottom = top + childHeight;
bottomBound = bottom + lp.bottomMargin;
}
// Update max
if (rightBound > maxRightNoPadding)
maxRightNoPadding = rightBound;
if (bottomBound > maxBottom)
maxBottom = bottomBound;
Rect rect = new Rect();
rect.left = left;
rect.top = top;
rect.right = right;
rect.bottom = bottom;
rectList.add(rect);
}
// Handle last line baseline
adjustBaseLine(maxBottom - lastMaxBottom, lineStartIndex, rectList.size());
int measuredWidth;
int measuredHeight;
if (widthMode == MeasureSpec.EXACTLY)
measuredWidth = maxWidth;
else
measuredWidth = maxRightNoPadding + paddingRight;
if (heightMode == MeasureSpec.EXACTLY)
measuredHeight = maxHeight;
else {
measuredHeight = maxBottom + paddingBottom;
if (heightMode == MeasureSpec.AT_MOST)
measuredHeight = measuredHeight > maxHeight ? maxHeight : measuredHeight;
}
setMeasuredDimension(measuredWidth, measuredHeight);
}
// TODO Take vertical mode
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = rectList.size();
for (int i = 0; i < count; i++) {
final View child = this.getChildAt(i);
if (child.getVisibility() == View.GONE)
continue;
Rect rect = rectList.get(i);
child.layout(rect.left, rect.top, rect.right, rect.bottom);
}
}
@Override
public MarginLayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected MarginLayoutParams generateDefaultLayoutParams() {
return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
@Override
protected MarginLayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new MarginLayoutParams(p);
}
public enum Alignment {
TOP(0),
CENTER(1),
BOTTOM(2);
final int nativeInt;
Alignment(int ni) {
nativeInt = ni;
}
}
}
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2022 Tarsin Norbin
~
~ This file is part of EhViewer
~
~ EhViewer 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.
~
~ EhViewer 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 EhViewer.
~ If not, see <https://www.gnu.org/licenses/>.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
<corners android:radius="64dp" />
</shape>
</item>
</ripple>
@@ -40,10 +40,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include
android:id="@+id/tags"
layout="@layout/gallery_detail_tags" />
<include
android:id="@+id/comments"
layout="@layout/gallery_detail_comments" />
@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2015 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/keyline_margin">
<TextView
android:id="@+id/no_tags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/no_tags" />
</LinearLayout>
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2016 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingLeft="@dimen/keyline_margin"
android:paddingRight="@dimen/keyline_margin" />
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2016 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/CardMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:background="@drawable/round_side_rect"
android:paddingLeft="12dp"
android:paddingTop="4dp"
android:paddingRight="12dp"
android:paddingBottom="4dp" />
-2
View File
@@ -18,8 +18,6 @@
<declare-styleable name="Theme">
<attr name="dividerColor" format="color" />
<attr name="tagGroupBackgroundColor" format="color" />
<attr name="tagBackgroundColor" format="color" />
</declare-styleable>
<declare-styleable name="ProgressView">
-2
View File
@@ -18,8 +18,6 @@
<style name="Base.AppTheme" parent="Theme.Material3.DynamicColors.DayNight">
<item name="dividerColor">@color/divider</item>
<item name="tagGroupBackgroundColor">?attr/colorPrimaryContainer</item>
<item name="tagBackgroundColor">?attr/colorTertiaryContainer</item>
<item name="preferenceTheme">@style/PreferenceThemeOverlay.Rikka.Material3</item>
<item name="snackbarStyle">@style/Snackbar</item>
<item name="snackbarButtonStyle">@style/SnackbarButton</item>