From 1b326a86a2023f602fdd2171463c57de322a765e Mon Sep 17 00:00:00 2001 From: tarsin Date: Tue, 15 Nov 2022 21:38:27 +0800 Subject: [PATCH] Convert GalleryInfoScene to BottomSheet, Resolve #354 --- .../com/hippo/ehviewer/ui/MainActivity.java | 2 - .../ehviewer/ui/scene/GalleryDetailScene.java | 7 +- .../ui/scene/GalleryInfoBottomSheet.kt | 200 +++++++++++++ .../ehviewer/ui/scene/GalleryInfoScene.java | 264 ------------------ .../main/res/layout/scene_gallery_info.xml | 26 +- app/src/main/res/values/styles.xml | 3 +- app/src/main/res/values/themes.xml | 6 + 7 files changed, 234 insertions(+), 274 deletions(-) create mode 100644 app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoBottomSheet.kt delete mode 100644 app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoScene.java diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java index 04f0676f2..5e8592d34 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java @@ -61,7 +61,6 @@ import com.hippo.ehviewer.ui.scene.DownloadsScene; import com.hippo.ehviewer.ui.scene.FavoritesScene; import com.hippo.ehviewer.ui.scene.GalleryCommentsScene; import com.hippo.ehviewer.ui.scene.GalleryDetailScene; -import com.hippo.ehviewer.ui.scene.GalleryInfoScene; import com.hippo.ehviewer.ui.scene.GalleryListScene; import com.hippo.ehviewer.ui.scene.GalleryPreviewsScene; import com.hippo.ehviewer.ui.scene.HistoryScene; @@ -101,7 +100,6 @@ public final class MainActivity extends StageActivity registerLaunchMode(SelectSiteScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); registerLaunchMode(GalleryListScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TOP); registerLaunchMode(GalleryDetailScene.class, SceneFragment.LAUNCH_MODE_STANDARD); - registerLaunchMode(GalleryInfoScene.class, SceneFragment.LAUNCH_MODE_STANDARD); registerLaunchMode(GalleryCommentsScene.class, SceneFragment.LAUNCH_MODE_STANDARD); registerLaunchMode(GalleryPreviewsScene.class, SceneFragment.LAUNCH_MODE_STANDARD); registerLaunchMode(DownloadsScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java index 4532097bf..ad3432339 100755 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java @@ -122,7 +122,6 @@ import com.hippo.yorozuya.IntIdGenerator; import com.hippo.yorozuya.SimpleHandler; import com.hippo.yorozuya.ViewUtils; import com.hippo.yorozuya.collect.IntList; -import com.hippo.yorozuya.collect.LongList; import java.io.File; import java.io.FileNotFoundException; @@ -1240,9 +1239,9 @@ public class GalleryDetailScene extends ToolbarScene implements View.OnClickList .show(); } } else if (mInfo == v) { - Bundle args = new Bundle(); - args.putParcelable(GalleryInfoScene.KEY_GALLERY_DETAIL, mGalleryDetail); - startScene(new Announcer(GalleryInfoScene.class).setArgs(args)); + assert mGalleryDetail != null; + var galleryInfoBottomSheet = new GalleryInfoBottomSheet(mGalleryDetail); + galleryInfoBottomSheet.show(requireActivity().getSupportFragmentManager(), GalleryInfoBottomSheet.TAG); } else if (mHeart == v || mHeartOutline == v) { if (mGalleryDetail != null && !mModifingFavorites) { boolean remove = false; diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoBottomSheet.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoBottomSheet.kt new file mode 100644 index 000000000..31de15f8c --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoBottomSheet.kt @@ -0,0 +1,200 @@ +/* + * 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. + */ +package com.hippo.ehviewer.ui.scene + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.TextView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import com.hippo.easyrecyclerview.EasyRecyclerView +import com.hippo.ehviewer.R +import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.UrlOpener +import com.hippo.ehviewer.client.EhUrl +import com.hippo.ehviewer.client.EhUtils +import com.hippo.ehviewer.client.data.GalleryDetail +import com.hippo.ehviewer.ui.MainActivity +import com.hippo.ehviewer.ui.scene.BaseScene.LENGTH_SHORT +import com.hippo.util.addTextToClipboard +import com.hippo.util.getClipboardManager + +class GalleryInfoBottomSheet(detail: GalleryDetail) : BottomSheetDialogFragment() { + private var mKeys: ArrayList = arrayListOf() + private var mValues: ArrayList = arrayListOf() + private var mRecyclerView: EasyRecyclerView? = null + private val mDetail: GalleryDetail = detail + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + parseDetail() + val view = inflater.inflate(R.layout.scene_gallery_info, container, false) + dialog?.window?.run { + addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND) + addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + attributes.blurBehindRadius = 32 + } + val recyclerView = view.findViewById(R.id.recycler_view) as EasyRecyclerView + val adapter = InfoAdapter() + recyclerView.adapter = adapter + recyclerView.layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false) + recyclerView.clipToPadding = false + recyclerView.setHasFixedSize(true) + mRecyclerView = recyclerView + return view + } + + private fun parseDetail() { + mKeys.add(getString(R.string.header_key)) + mValues.add(getString(R.string.header_value)) + mKeys.add(getString(R.string.key_gid)) + mValues.add(mDetail.gid.toString()) + mKeys.add(getString(R.string.key_token)) + mValues.add(mDetail.token) + mKeys.add(getString(R.string.key_url)) + mValues.add(EhUrl.getGalleryDetailUrl(mDetail.gid, mDetail.token)) + mKeys.add(getString(R.string.key_title)) + mValues.add(mDetail.title) + mKeys.add(getString(R.string.key_title_jpn)) + mValues.add(mDetail.titleJpn) + mKeys.add(getString(R.string.key_thumb)) + mValues.add(mDetail.thumb) + mKeys.add(getString(R.string.key_category)) + mValues.add(EhUtils.getCategory(mDetail.category)) + mKeys.add(getString(R.string.key_uploader)) + mValues.add(mDetail.uploader) + mKeys.add(getString(R.string.key_posted)) + mValues.add(mDetail.posted) + mKeys.add(getString(R.string.key_parent)) + mValues.add(mDetail.parent) + mKeys.add(getString(R.string.key_visible)) + mValues.add(mDetail.visible) + mKeys.add(getString(R.string.key_language)) + mValues.add(mDetail.language) + mKeys.add(getString(R.string.key_pages)) + mValues.add(mDetail.pages.toString()) + mKeys.add(getString(R.string.key_size)) + mValues.add(mDetail.size) + mKeys.add(getString(R.string.key_favorite_count)) + mValues.add(mDetail.favoriteCount.toString()) + mKeys.add(getString(R.string.key_favorited)) + mValues.add(java.lang.Boolean.toString(mDetail.isFavorited)) + mKeys.add(getString(R.string.key_rating_count)) + mValues.add(mDetail.ratingCount.toString()) + mKeys.add(getString(R.string.key_rating)) + mValues.add(mDetail.rating.toString()) + mKeys.add(getString(R.string.key_torrents)) + mValues.add(mDetail.torrentCount.toString()) + mKeys.add(getString(R.string.key_torrent_url)) + mValues.add(mDetail.torrentUrl) + mKeys.add(getString(R.string.favorite_name)) + mValues.add(mDetail.favoriteName) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + (view.findViewById(R.id.title) as TextView).setText(R.string.gallery_info) + } + + override fun onDestroyView() { + super.onDestroyView() + mRecyclerView?.stopScroll() + } + + fun onItemClick(position: Int): Boolean { + val context = context + return if (null != context && 0 != position) { + if (position == INDEX_PARENT) { + UrlOpener.openUrl(context, mValues[position], true) + } else { + requireContext().getClipboardManager().addTextToClipboard( + mValues[position], + false + ) { + (requireActivity() as MainActivity).showTip( + R.string.copied_to_clipboard, + LENGTH_SHORT + ) + } + if (position == INDEX_URL) { + // Save it to avoid detect the gallery + Settings.putClipboardTextHashCode(mValues[position].hashCode()) + } + } + true + } else { + false + } + } + + private class InfoHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val key: TextView + val value: TextView + + init { + key = itemView.findViewById(R.id.key) + value = itemView.findViewById(R.id.value) + } + } + + private inner class InfoAdapter : RecyclerView.Adapter() { + private val mInflater: LayoutInflater = layoutInflater + + override fun getItemViewType(position: Int): Int { + return if (position == 0) { + TYPE_HEADER + } else { + TYPE_DATA + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InfoHolder { + return InfoHolder( + mInflater.inflate( + if (viewType == Companion.TYPE_HEADER) R.layout.item_gallery_info_header else R.layout.item_gallery_info_data, + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: InfoHolder, position: Int) { + holder.key.text = mKeys[position] + holder.value.text = mValues[position] + holder.itemView.isEnabled = position != 0 + holder.itemView.setOnClickListener { onItemClick(position) } + } + + override fun getItemCount(): Int { + return mKeys.size.coerceAtMost(mValues.size) + } + } + + companion object { + const val TAG = "GalleryInfoBottomSheet" + private const val INDEX_URL = 3 + private const val INDEX_PARENT = 10 + private const val TYPE_HEADER = 0 + private const val TYPE_DATA = 1 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoScene.java deleted file mode 100644 index 0e6f14818..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryInfoScene.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * 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. - */ - -package com.hippo.ehviewer.ui.scene; - -import android.content.Context; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.hippo.easyrecyclerview.EasyRecyclerView; -import com.hippo.ehviewer.R; -import com.hippo.ehviewer.Settings; -import com.hippo.ehviewer.UrlOpener; -import com.hippo.ehviewer.client.EhUrl; -import com.hippo.ehviewer.client.EhUtils; -import com.hippo.ehviewer.client.data.GalleryDetail; -import com.hippo.util.ClipboardUtilKt; -import com.hippo.yorozuya.AssertUtils; -import com.hippo.yorozuya.ViewUtils; - -import java.util.ArrayList; - -public final class GalleryInfoScene extends ToolbarScene { - - public static final String KEY_GALLERY_DETAIL = "gallery_detail"; - public static final String KEY_KEYS = "keys"; - public static final String KEY_VALUES = "values"; - - private static final int INDEX_URL = 3; - private static final int INDEX_PARENT = 10; - - /*--------------- - Whole life cycle - ---------------*/ - @Nullable - private ArrayList mKeys; - @Nullable - private ArrayList mValues; - - @Nullable - private EasyRecyclerView mRecyclerView; - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (savedInstanceState == null) { - onInit(); - } else { - onRestore(savedInstanceState); - } - } - - private void handlerArgs(Bundle args) { - if (args == null) { - return; - } - GalleryDetail gd = args.getParcelable(KEY_GALLERY_DETAIL); - if (gd == null) { - return; - } - if (mKeys == null || mValues == null) { - return; - } - - mKeys.add(getString(R.string.header_key)); - mValues.add(getString(R.string.header_value)); - mKeys.add(getString(R.string.key_gid)); - mValues.add(Long.toString(gd.gid)); - mKeys.add(getString(R.string.key_token)); - mValues.add(gd.token); - mKeys.add(getString(R.string.key_url)); - mValues.add(EhUrl.getGalleryDetailUrl(gd.gid, gd.token)); - mKeys.add(getString(R.string.key_title)); - mValues.add(gd.title); - mKeys.add(getString(R.string.key_title_jpn)); - mValues.add(gd.titleJpn); - mKeys.add(getString(R.string.key_thumb)); - mValues.add(gd.thumb); - mKeys.add(getString(R.string.key_category)); - mValues.add(EhUtils.getCategory(gd.category)); - mKeys.add(getString(R.string.key_uploader)); - mValues.add(gd.uploader); - mKeys.add(getString(R.string.key_posted)); - mValues.add(gd.posted); - mKeys.add(getString(R.string.key_parent)); - mValues.add(gd.parent); - mKeys.add(getString(R.string.key_visible)); - mValues.add(gd.visible); - mKeys.add(getString(R.string.key_language)); - mValues.add(gd.language); - mKeys.add(getString(R.string.key_pages)); - mValues.add(Integer.toString(gd.pages)); - mKeys.add(getString(R.string.key_size)); - mValues.add(gd.size); - mKeys.add(getString(R.string.key_favorite_count)); - mValues.add(Integer.toString(gd.favoriteCount)); - mKeys.add(getString(R.string.key_favorited)); - mValues.add(Boolean.toString(gd.isFavorited)); - mKeys.add(getString(R.string.key_rating_count)); - mValues.add(Integer.toString(gd.ratingCount)); - mKeys.add(getString(R.string.key_rating)); - mValues.add(Float.toString(gd.rating)); - mKeys.add(getString(R.string.key_torrents)); - mValues.add(Integer.toString(gd.torrentCount)); - mKeys.add(getString(R.string.key_torrent_url)); - mValues.add(gd.torrentUrl); - mKeys.add(getString(R.string.favorite_name)); - mValues.add(gd.favoriteName); - } - - protected void onInit() { - mKeys = new ArrayList<>(); - mValues = new ArrayList<>(); - handlerArgs(getArguments()); - } - - protected void onRestore(@NonNull Bundle savedInstanceState) { - mKeys = savedInstanceState.getStringArrayList(KEY_KEYS); - mValues = savedInstanceState.getStringArrayList(KEY_VALUES); - } - - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - outState.putStringArrayList(KEY_KEYS, mKeys); - outState.putStringArrayList(KEY_VALUES, mValues); - } - - @Override - public View onCreateViewWithToolbar(LayoutInflater inflater, - @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.scene_gallery_info, container, false); - - Context context = getContext(); - AssertUtils.assertNotNull(context); - - mRecyclerView = (EasyRecyclerView) ViewUtils.$$(view, R.id.recycler_view); - InfoAdapter adapter = new InfoAdapter(); - mRecyclerView.setAdapter(adapter); - mRecyclerView.setLayoutManager(new LinearLayoutManager(context, RecyclerView.VERTICAL, false)); - mRecyclerView.setClipToPadding(false); - mRecyclerView.setHasFixedSize(true); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setTitle(R.string.gallery_info); - setNavigationIcon(R.drawable.v_arrow_left_dark_x24); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - - if (null != mRecyclerView) { - mRecyclerView.stopScroll(); - mRecyclerView = null; - } - } - - public boolean onItemClick(int position) { - Context context = getContext(); - if (null != context && 0 != position && null != mValues) { - if (position == INDEX_PARENT) { - UrlOpener.openUrl(context, mValues.get(position), true); - } else { - ClipboardUtilKt.addTextToClipboard(ClipboardUtilKt.getClipboardManager(getContext()), mValues.get(position), false, () -> showTip(R.string.copied_to_clipboard, LENGTH_SHORT)); - if (position == INDEX_URL) { - // Save it to avoid detect the gallery - Settings.putClipboardTextHashCode(mValues.get(position).hashCode()); - } - } - return true; - } else { - return false; - } - } - - @Override - public void onNavigationClick() { - onBackPressed(); - } - - private static class InfoHolder extends RecyclerView.ViewHolder { - - private final TextView key; - private final TextView value; - - public InfoHolder(View itemView) { - super(itemView); - - key = itemView.findViewById(R.id.key); - value = itemView.findViewById(R.id.value); - } - } - - private class InfoAdapter extends RecyclerView.Adapter { - - private static final int TYPE_HEADER = 0; - private static final int TYPE_DATA = 1; - - private final LayoutInflater mInflater; - - public InfoAdapter() { - mInflater = getLayoutInflater(); - AssertUtils.assertNotNull(mInflater); - } - - @Override - public int getItemViewType(int position) { - if (position == 0) { - return TYPE_HEADER; - } else { - return TYPE_DATA; - } - } - - @NonNull - @Override - public InfoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - return new InfoHolder(mInflater.inflate(viewType == TYPE_HEADER ? - R.layout.item_gallery_info_header : R.layout.item_gallery_info_data, parent, false)); - } - - @Override - public void onBindViewHolder(@NonNull InfoHolder holder, int position) { - if (mKeys != null && mValues != null) { - holder.key.setText(mKeys.get(position)); - holder.value.setText(mValues.get(position)); - holder.itemView.setEnabled(position != 0); - holder.itemView.setOnClickListener(v -> onItemClick(position)); - } - } - - @Override - public int getItemCount() { - return mKeys == null || mValues == null ? 0 : Math.min(mKeys.size(), mValues.size()); - } - } -} diff --git a/app/src/main/res/layout/scene_gallery_info.xml b/app/src/main/res/layout/scene_gallery_info.xml index 5ea92d450..4e5bae58c 100644 --- a/app/src/main/res/layout/scene_gallery_info.xml +++ b/app/src/main/res/layout/scene_gallery_info.xml @@ -14,9 +14,29 @@ ~ limitations under the License. --> - + android:orientation="vertical"> + + + + + + + + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 82a3bd393..7c73b8439 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -15,8 +15,9 @@ --> + + +