From 6ceb50c0bd71fe2e380b096d640a1cfb7e78c1a2 Mon Sep 17 00:00:00 2001 From: tarsin Date: Thu, 16 Mar 2023 23:19:54 +0800 Subject: [PATCH] Convert galleryDetail tags to compose --- .../ehviewer/ui/scene/GalleryDetailScene.kt | 176 ++++++------ .../java/com/hippo/widget/AutoWrapLayout.java | 266 ------------------ app/src/main/res/drawable/round_side_rect.xml | 26 -- .../res/layout/gallery_detail_content.xml | 4 - .../main/res/layout/gallery_detail_tags.xml | 31 -- app/src/main/res/layout/gallery_tag_group.xml | 22 -- app/src/main/res/layout/item_gallery_tag.xml | 26 -- app/src/main/res/values/attrs.xml | 2 - app/src/main/res/values/themes.xml | 2 - 9 files changed, 85 insertions(+), 470 deletions(-) delete mode 100644 app/src/main/java/com/hippo/widget/AutoWrapLayout.java delete mode 100644 app/src/main/res/drawable/round_side_rect.xml delete mode 100644 app/src/main/res/layout/gallery_detail_tags.xml delete mode 100644 app/src/main/res/layout/gallery_tag_group.xml delete mode 100644 app/src/main/res/layout/item_gallery_tag.xml diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt index 9f17e6b47..c264e6e79 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.kt @@ -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?) { - 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) { + + @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) { diff --git a/app/src/main/java/com/hippo/widget/AutoWrapLayout.java b/app/src/main/java/com/hippo/widget/AutoWrapLayout.java deleted file mode 100644 index f448ce6a9..000000000 --- a/app/src/main/java/com/hippo/widget/AutoWrapLayout.java +++ /dev/null @@ -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 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 - *

- * 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; - } - } -} diff --git a/app/src/main/res/drawable/round_side_rect.xml b/app/src/main/res/drawable/round_side_rect.xml deleted file mode 100644 index 226bd4698..000000000 --- a/app/src/main/res/drawable/round_side_rect.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/gallery_detail_content.xml b/app/src/main/res/layout/gallery_detail_content.xml index 9e861fbee..b70e3ecf0 100644 --- a/app/src/main/res/layout/gallery_detail_content.xml +++ b/app/src/main/res/layout/gallery_detail_content.xml @@ -40,10 +40,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> - - diff --git a/app/src/main/res/layout/gallery_detail_tags.xml b/app/src/main/res/layout/gallery_detail_tags.xml deleted file mode 100644 index 607c41769..000000000 --- a/app/src/main/res/layout/gallery_detail_tags.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/layout/gallery_tag_group.xml b/app/src/main/res/layout/gallery_tag_group.xml deleted file mode 100644 index e98cd001d..000000000 --- a/app/src/main/res/layout/gallery_tag_group.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - diff --git a/app/src/main/res/layout/item_gallery_tag.xml b/app/src/main/res/layout/item_gallery_tag.xml deleted file mode 100644 index f77b91793..000000000 --- a/app/src/main/res/layout/item_gallery_tag.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index e0e16601a..5d92db5ac 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -18,8 +18,6 @@ - - diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 24ec900ba..603d33ebc 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -18,8 +18,6 @@