Rewrite gallery detail actions with compose

This commit is contained in:
tarsin committed 2023-03-16 19:05:48 +08:00
1 parent 8621de6d09
commit 1333aa10f8
3 files changed
+276 -318

No files matched your search

@@ -43,18 +43,39 @@ import android.widget.TextView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.IntDef
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CloudDone
import androidx.compose.material.icons.filled.Difference
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.ImageSearch
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.SwapVerticalCircle
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
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
@@ -384,20 +405,6 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
binding.tip.setCompoundDrawables(null, drawable, null, null)
binding.tip.setOnClickListener(this)
binding.content.actions.let {
it.newerVersion.setOnClickListener(this)
it.heart.setOnClickListener(this)
it.heart.setOnLongClickListener(this)
it.heartOutline.setOnClickListener(this)
it.heartOutline.setOnLongClickListener(this)
it.torrent.setOnClickListener(this)
it.archive.setOnClickListener(this)
it.share.setOnClickListener(this)
it.rate.setOnClickListener(this)
it.similar.setOnClickListener(this)
it.searchCover.setOnClickListener(this)
}
binding.content.actions.newerVersion.setOnClickListener(this)
if (Settings.showComments) {
binding.content.comments.comments.setOnClickListener(this)
} else {
@@ -623,6 +630,107 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
}
}
}
@Composable
fun EhIconButton(
icon: ImageVector,
text: String,
onClick: () -> Unit,
) {
OutlinedButton(
onClick = onClick,
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
modifier = Modifier.padding(end = 8.dp)
) {
Icon(
imageVector = icon,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
Text(text = text)
}
}
@Composable
fun EhAccentIconButton(
icon: ImageVector,
text: String,
onClick: () -> Unit,
) {
Button(
onClick = onClick,
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.onSecondaryContainer),
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
modifier = Modifier.padding(end = 8.dp)
) {
Icon(
imageVector = icon,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
Text(text = text)
}
}
binding.content.actions.setContent {
Mdc3Theme {
Column(
modifier = Modifier
.padding(horizontal = dimensionResource(id = R.dimen.keyline_margin))
.padding(top = dimensionResource(id = R.dimen.keyline_margin))
) {
if (!composeBindingGD?.newerVersions.isNullOrEmpty()) {
Box(
contentAlignment = Alignment.Center
) {
Card(onClick = ::showNewerVersionDialog) {}
Text(text = stringResource(id = R.string.newer_version_avaliable))
}
}
FlowRow {
if (favourite) {
EhAccentIconButton(
icon = Icons.Default.Favorite,
text = favButtonText,
onClick = ::modifyFavourite
)
} else {
EhIconButton(
icon = Icons.Default.FavoriteBorder,
text = stringResource(id = R.string.not_favorited),
onClick = ::modifyFavourite
)
}
EhIconButton(
icon = Icons.Default.Difference,
text = stringResource(id = R.string.similar_gallery),
onClick = ::showSimilarGalleryList
)
EhIconButton(
icon = Icons.Default.ImageSearch,
text = stringResource(id = R.string.search_cover),
onClick = ::showCoverGalleryList
)
EhIconButton(
icon = Icons.Default.Share,
text = stringResource(id = R.string.share),
onClick = ::doShareGallery
)
EhIconButton(
icon = Icons.Default.SwapVerticalCircle,
text = torrentText,
onClick = ::showTorrentDialog
)
EhIconButton(
icon = Icons.Default.CloudDone,
text = stringResource(id = R.string.archive),
onClick = ::showArchiveDialog
)
}
}
}
}
mGalleryInfo?.let { gi ->
if (mAction == ACTION_GALLERY_INFO) {
binding.content.header.run {
@@ -634,30 +742,99 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
}
}
private fun doShareGallery() {
galleryDetailUrl?.let { AppHelper.share(requireActivity(), it) }
}
private var torrentText by mutableStateOf("")
private var favourite by mutableStateOf(false)
private var favButtonText by mutableStateOf("")
private fun updateFavoriteDrawable() {
val gd = mGalleryDetail ?: return
_binding ?: return
binding.content.actions.run {
lifecycleScope.launchIO {
val containLocalFav = EhDB.containLocalFavorites(gd.gid)
withUIContext {
if (gd.isFavorited || containLocalFav) {
heart.visibility = View.VISIBLE
if (gd.favoriteName == null) {
heart.setText(R.string.local_favorites)
} else {
heart.text = gd.favoriteName
}
heartOutline.visibility = View.GONE
} else {
heart.visibility = View.GONE
heartOutline.visibility = View.VISIBLE
}
if (gd.isFavorited || containLocalFav) {
favourite = true
favButtonText = gd.favoriteName ?: getString(R.string.local_favorites)
} else {
favourite = false
}
}
}
}
private fun modifyFavourite() {
val galleryDetail = mGalleryDetail ?: return
lifecycleScope.launchIO {
if (!mModifyingFavorites) {
var remove = false
val containLocalFavorites =
EhDB.containLocalFavorites(galleryDetail.gid)
if (containLocalFavorites || galleryDetail.isFavorited) {
mModifyingFavorites = true
CommonOperations.removeFromFavorites(
activity, galleryDetail,
ModifyFavoritesListener(requireContext(), true)
)
remove = true
}
withUIContext {
if (!remove) {
mModifyingFavorites = true
CommonOperations.addToFavorites(
requireActivity(), galleryDetail,
ModifyFavoritesListener(requireContext(), false)
)
}
// Update UI
updateFavoriteDrawable()
}
}
}
}
private fun showNewerVersionDialog() {
val galleryDetail = mGalleryDetail ?: return
val titles = ArrayList<CharSequence>()
for (newerVersion in galleryDetail.newerVersions) {
titles.add(
getString(
R.string.newer_version_title,
newerVersion.title,
newerVersion.posted
)
)
}
BaseDialogBuilder(requireContext())
.setItems(titles.toTypedArray()) { _: DialogInterface?, which: Int ->
val newerVersion = galleryDetail.newerVersions[which]
val args = Bundle()
args.putString(KEY_ACTION, ACTION_GID_TOKEN)
args.putLong(KEY_GID, newerVersion.gid)
args.putString(KEY_TOKEN, newerVersion.token)
navigate(R.id.galleryDetailScene, args)
}
.show()
}
private fun showArchiveDialog() {
val galleryDetail = mGalleryDetail ?: return
if (galleryDetail.apiUid < 0) {
showTip(R.string.sign_in_first, LENGTH_LONG)
return
}
val helper = ArchiveListDialogHelper()
val dialog: Dialog = BaseDialogBuilder(requireContext())
.setTitle(R.string.settings_download)
.setView(R.layout.dialog_archive_list)
.setOnDismissListener(helper)
.show()
helper.setDialog(dialog, galleryDetail.archiveUrl)
}
private fun bindViewSecond() {
val gd = mGalleryDetail ?: return
if (mPage != 0) {
@@ -676,29 +853,19 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
.show()
}
_binding ?: return
val resources = resources
composeBindingGI = gd
composeBindingGD = gd
setTitle(EhUtils.getSuitableTitle(gd))
updateDownloadText()
updateFavoriteDrawable()
/*
binding.content.header.run {
language.text = gd.language
pages.text = resources.getQuantityString(R.plurals.page_count, gd.pages, gd.pages)
size.text = gd.size
posted.text = gd.posted
favoredTimes.text = resources.getString(R.string.favored_times, gd.favoriteCount)
}
*/
if (gd.newerVersions.size != 0) {
binding.content.actions.newerVersion.visibility = View.VISIBLE
}
binding.content.actions.run {
ratingText.text = getAllRatingText(gd.rating, gd.ratingCount)
rating.rating = gd.rating
updateFavoriteDrawable()
torrent.text = resources.getString(R.string.torrent_count, gd.torrentCount)
}
*/
torrentText = resources.getString(R.string.torrent_count, gd.torrentCount)
bindTags(gd.tags)
bindComments(gd.comments!!.comments)
bindPreviews(gd)
@@ -883,6 +1050,41 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
}
}
private fun showTorrentDialog() {
val galleryDetail = mGalleryDetail ?: return
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
requestStoragePermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} else {
val helper = TorrentListDialogHelper()
val dialog: Dialog = BaseDialogBuilder(requireContext())
.setTitle(R.string.torrents)
.setView(R.layout.dialog_torrent_list)
.setOnDismissListener(helper)
.show()
helper.setDialog(dialog, galleryDetail.torrentUrl)
}
}
private fun showRateDialog() {
val galleryDetail = mGalleryDetail ?: return
if (galleryDetail.apiUid < 0) {
showTip(R.string.sign_in_first, LENGTH_LONG)
return
}
val helper = RateDialogHelper()
val dialog: Dialog = BaseDialogBuilder(requireContext())
.setTitle(R.string.rate)
.setView(R.layout.dialog_rate)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, helper)
.show()
helper.setDialog(dialog, galleryDetail.rating)
}
override fun onClick(v: View) {
val context = context
val activity = mainActivity
@@ -898,119 +1100,6 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
val galleryDetail = mGalleryDetail ?: return
when (v) {
binding.content.actions.newerVersion -> {
val titles = ArrayList<CharSequence>()
for (newerVersion in galleryDetail.newerVersions) {
titles.add(
getString(
R.string.newer_version_title,
newerVersion.title,
newerVersion.posted
)
)
}
BaseDialogBuilder(requireContext())
.setItems(titles.toTypedArray()) { _: DialogInterface?, which: Int ->
val newerVersion = galleryDetail.newerVersions[which]
val args = Bundle()
args.putString(KEY_ACTION, ACTION_GID_TOKEN)
args.putLong(KEY_GID, newerVersion.gid)
args.putString(KEY_TOKEN, newerVersion.token)
navigate(R.id.galleryDetailScene, args)
}
.show()
}
binding.content.actions.heart,
binding.content.actions.heartOutline -> {
lifecycleScope.launchIO {
if (!mModifyingFavorites) {
var remove = false
val containLocalFavorites = EhDB.containLocalFavorites(galleryDetail.gid)
if (containLocalFavorites || galleryDetail.isFavorited) {
mModifyingFavorites = true
CommonOperations.removeFromFavorites(
activity, galleryDetail,
ModifyFavoritesListener(context, true)
)
remove = true
}
withUIContext {
if (!remove) {
mModifyingFavorites = true
CommonOperations.addToFavorites(
activity, galleryDetail,
ModifyFavoritesListener(context, false)
)
}
// Update UI
updateFavoriteDrawable()
}
}
}
}
binding.content.actions.share -> {
galleryDetailUrl?.let {
AppHelper.share(activity, it)
}
}
binding.content.actions.torrent -> {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(
activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) != PackageManager.PERMISSION_GRANTED
) {
requestStoragePermissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
} else {
val helper = TorrentListDialogHelper()
val dialog: Dialog = BaseDialogBuilder(context)
.setTitle(R.string.torrents)
.setView(R.layout.dialog_torrent_list)
.setOnDismissListener(helper)
.show()
helper.setDialog(dialog, galleryDetail.torrentUrl)
}
}
binding.content.actions.archive -> {
if (galleryDetail.apiUid < 0) {
showTip(R.string.sign_in_first, LENGTH_LONG)
return
}
val helper = ArchiveListDialogHelper()
val dialog: Dialog = BaseDialogBuilder(context)
.setTitle(R.string.settings_download)
.setView(R.layout.dialog_archive_list)
.setOnDismissListener(helper)
.show()
helper.setDialog(dialog, galleryDetail.archiveUrl)
}
binding.content.actions.rate -> {
if (galleryDetail.apiUid < 0) {
showTip(R.string.sign_in_first, LENGTH_LONG)
return
}
val helper = RateDialogHelper()
val dialog: Dialog = BaseDialogBuilder(context)
.setTitle(R.string.rate)
.setView(R.layout.dialog_rate)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, helper)
.show()
helper.setDialog(dialog, galleryDetail.rating)
}
binding.content.actions.similar -> {
showSimilarGalleryList()
}
binding.content.actions.searchCover -> {
showCoverGalleryList()
}
binding.content.comments.comments -> {
val args = Bundle()
args.putLong(GalleryCommentsScene.KEY_API_UID, galleryDetail.apiUid)
@@ -1132,39 +1221,38 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
request.enqueue(this)
}
override fun onLongClick(v: View): Boolean {
val activity = mainActivity ?: return false
if (binding.content.actions.heart === v || binding.content.actions.heartOutline === v) {
lifecycleScope.launchIO {
if (mGalleryDetail != null && !mModifyingFavorites) {
var remove = false
if (EhDB.containLocalFavorites(mGalleryDetail!!.gid) || mGalleryDetail!!.isFavorited) {
private fun modifyFavouriteLongClick() {
lifecycleScope.launchIO {
if (mGalleryDetail != null && !mModifyingFavorites) {
var remove = false
if (EhDB.containLocalFavorites(mGalleryDetail!!.gid) || mGalleryDetail!!.isFavorited) {
mModifyingFavorites = true
CommonOperations.removeFromFavorites(
activity, mGalleryDetail!!,
ModifyFavoritesListener(requireActivity(), true)
)
remove = true
}
withUIContext {
if (!remove) {
mModifyingFavorites = true
CommonOperations.removeFromFavorites(
activity, mGalleryDetail!!,
ModifyFavoritesListener(activity, true)
CommonOperations.addToFavorites(
requireActivity(), mGalleryDetail!!,
ModifyFavoritesListener(requireActivity(), false), true
)
remove = true
}
withUIContext {
if (!remove) {
mModifyingFavorites = true
CommonOperations.addToFavorites(
activity, mGalleryDetail!!,
ModifyFavoritesListener(activity, false), true
)
}
// Update UI
updateFavoriteDrawable()
}
// Update UI
updateFavoriteDrawable()
}
}
} else {
val tag = v.getTag(R.id.tag) as? String
if (null != tag) {
showTagDialog(v as TextView, tag)
return true
}
}
}
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
}
@@ -1248,10 +1336,13 @@ class GalleryDetailScene : CollapsingToolbarScene(), View.OnClickListener, Downl
// Update UI
_binding ?: return
/*
binding.content.actions.run {
ratingText.text = getAllRatingText(result.rating, result.ratingCount)
rating.rating = result.rating
}
*/
}
private fun onModifyFavoritesSuccess(addOrRemove: Boolean) {
@@ -1,134 +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"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="@dimen/keyline_margin">
<TextView
android:id="@+id/newerVersion"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:gravity="center"
android:padding="8dp"
android:text="@string/newer_version_avaliable"
android:visibility="gone" />
<HorizontalScrollView
android:id="@+id/actions_scroll_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:clipToPadding="false"
android:paddingLeft="@dimen/keyline_margin"
android:paddingRight="@dimen/keyline_margin"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/heart"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/favorited"
app:backgroundTint="?colorAccent"
app:icon="@drawable/v_heart_primary_x48" />
<Button
android:id="@+id/heart_outline"
style="@style/Widget.Material3.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/not_favorited"
app:icon="@drawable/v_heart_outline_primary_x48" />
<Button
android:id="@+id/similar"
style="@style/Widget.Material3.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/similar_gallery"
app:icon="@drawable/v_similar_primary_x48" />
<Button
android:id="@+id/search_cover"
style="@style/Widget.Material3.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/search_cover"
app:icon="@drawable/v_file_find_primary_x48" />
<Button
android:id="@+id/share"
style="@style/Widget.Material3.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/share"
app:icon="@drawable/v_share_primary_x48" />
<Button
android:id="@+id/torrent"
style="@style/Widget.Material3.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/v_utorrent_primary_x48" />
<Button
android:id="@+id/archive"
style="@style/Widget.Material3.Button.IconButton.Outlined"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/archive"
app:icon="@drawable/v_archive_primary_x48" />
</LinearLayout>
</HorizontalScrollView>
<LinearLayout
android:id="@+id/rate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground"
android:orientation="vertical"
android:paddingBottom="@dimen/keyline_margin">
<androidx.appcompat.widget.AppCompatRatingBar
android:id="@+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="8dp"
android:isIndicator="true"
android:theme="@style/RatingBarTheme" />
<TextView
android:id="@+id/rating_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
</LinearLayout>
@@ -35,9 +35,10 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<include
<androidx.compose.ui.platform.ComposeView
android:id="@+id/actions"
layout="@layout/gallery_detail_actions" />
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<include
android:id="@+id/tags"