mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-3263 Working code
This commit is contained in:
parent
c4f40d15c4
commit
a96ebb9aea
13 changed files with 199 additions and 49 deletions
|
@ -824,29 +824,28 @@ open class ObjectSetFragment :
|
|||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
binding.objectHeader.root.findViewById<View>(R.id.imageIcon).apply {
|
||||
if (header.title.image != null) visible() else gone()
|
||||
binding.objectHeader.root.findViewById<ImageView>(R.id.imageIcon).apply {
|
||||
jobs += this.clicks()
|
||||
.throttleFirst()
|
||||
.onEach { vm.onObjectIconClicked() }
|
||||
.launchIn(lifecycleScope)
|
||||
|
||||
if (header.title.image != null) {
|
||||
this.visible()
|
||||
Glide
|
||||
.with(this)
|
||||
.load(header.title.image)
|
||||
.centerCrop()
|
||||
.into(this)
|
||||
} else {
|
||||
this.gone()
|
||||
this.setImageDrawable(null)
|
||||
}
|
||||
}
|
||||
|
||||
binding.objectHeader.root.findViewById<ImageView>(R.id.emojiIcon)
|
||||
.setEmojiOrNull(header.title.emoji)
|
||||
|
||||
if (header.title.image != null) {
|
||||
binding.objectHeader.root.findViewById<ImageView>(R.id.imageIcon).apply {
|
||||
Glide
|
||||
.with(this)
|
||||
.load(header.title.image)
|
||||
.centerCrop()
|
||||
.into(this)
|
||||
}
|
||||
} else {
|
||||
binding.objectHeader.root.findViewById<ImageView>(R.id.imageIcon).setImageDrawable(null)
|
||||
}
|
||||
|
||||
setCover(
|
||||
coverColor = header.title.coverColor,
|
||||
coverGradient = header.title.coverGradient,
|
||||
|
|
|
@ -1339,7 +1339,8 @@ class BlockAdapter(
|
|||
bind(
|
||||
item = blocks[position] as BlockView.Title.Basic,
|
||||
onPageIconClicked = onPageIconClicked,
|
||||
onCoverClicked = onCoverClicked
|
||||
onCoverClicked = onCoverClicked,
|
||||
click = onClickListener
|
||||
)
|
||||
setTextInputClickListener {
|
||||
if (Build.VERSION.SDK_INT == N || Build.VERSION.SDK_INT == N_MR1) {
|
||||
|
@ -1356,7 +1357,8 @@ class BlockAdapter(
|
|||
bind(
|
||||
item = blocks[position] as BlockView.Title.Todo,
|
||||
onPageIconClicked = onPageIconClicked,
|
||||
onCoverClicked = onCoverClicked
|
||||
onCoverClicked = onCoverClicked,
|
||||
click = onClickListener
|
||||
)
|
||||
setTextInputClickListener {
|
||||
if (Build.VERSION.SDK_INT == N || Build.VERSION.SDK_INT == N_MR1) {
|
||||
|
@ -1373,7 +1375,8 @@ class BlockAdapter(
|
|||
bind(
|
||||
item = blocks[position] as BlockView.Title.Profile,
|
||||
onProfileIconClicked = onClickListener,
|
||||
onCoverClicked = onCoverClicked
|
||||
onCoverClicked = onCoverClicked,
|
||||
click = onClickListener
|
||||
)
|
||||
setTextInputClickListener {
|
||||
if (Build.VERSION.SDK_INT == N || Build.VERSION.SDK_INT == N_MR1) {
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.other
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import java.security.MessageDigest
|
||||
|
||||
class CustomImageResizeTransformation(
|
||||
private val maxWidth: Int,
|
||||
private val maxHeight: Int
|
||||
) : BitmapTransformation() {
|
||||
|
||||
override fun transform(
|
||||
pool: BitmapPool,
|
||||
toTransform: Bitmap,
|
||||
outWidth: Int,
|
||||
outHeight: Int
|
||||
): Bitmap {
|
||||
val imageWidth = toTransform.width
|
||||
val imageHeight = toTransform.height
|
||||
val targetAspectRatio = maxWidth.toFloat() / maxHeight
|
||||
|
||||
return when {
|
||||
imageWidth > maxWidth && imageHeight > maxHeight -> {
|
||||
val imageAspectRatio = imageWidth.toFloat() / imageHeight
|
||||
|
||||
if (imageAspectRatio > targetAspectRatio) {
|
||||
val cropWidth = (imageHeight * targetAspectRatio).toInt()
|
||||
val cropStartX = (imageWidth - cropWidth) / 2
|
||||
Bitmap.createBitmap(toTransform, cropStartX, 0, cropWidth, imageHeight)
|
||||
} else {
|
||||
val cropHeight = (imageWidth / targetAspectRatio).toInt()
|
||||
val cropStartY = (imageHeight - cropHeight) / 2
|
||||
Bitmap.createBitmap(toTransform, 0, cropStartY, imageWidth, cropHeight)
|
||||
}
|
||||
}
|
||||
imageWidth > maxWidth && imageHeight <= maxHeight -> {
|
||||
val scaleFactor = maxWidth.toFloat() / imageWidth
|
||||
val newHeight = (imageHeight * scaleFactor).toInt()
|
||||
Bitmap.createScaledBitmap(toTransform, maxWidth, newHeight, true)
|
||||
}
|
||||
imageHeight > maxHeight && imageWidth <= maxWidth -> {
|
||||
val cropHeight = (imageWidth / targetAspectRatio).toInt()
|
||||
val cropStartY = (imageHeight - cropHeight) / 2
|
||||
Bitmap.createBitmap(toTransform, 0, cropStartY, imageWidth, cropHeight)
|
||||
}
|
||||
else -> toTransform
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?) = other is CustomImageResizeTransformation
|
||||
override fun hashCode() = "CustomImageResizeTransformation".hashCode()
|
||||
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
|
||||
messageDigest.update("CustomImageResizeTransformation".toByteArray())
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
package com.anytypeio.anytype.core_ui.features.editor.holders.other
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.text.Spannable
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.FrameLayout.LayoutParams
|
||||
|
@ -38,6 +41,11 @@ import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
|
|||
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import java.security.MessageDigest
|
||||
import timber.log.Timber
|
||||
|
||||
sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
||||
|
@ -50,7 +58,8 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
|
||||
fun bind(
|
||||
item: BlockView.Title,
|
||||
onCoverClicked: () -> Unit
|
||||
onCoverClicked: () -> Unit,
|
||||
click: (ListenerType) -> Unit
|
||||
) {
|
||||
setImage(item)
|
||||
applyTextColor(item)
|
||||
|
@ -162,22 +171,34 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun setImage(item: BlockView.Title) {
|
||||
Timber.d("Setting image for ${item.id}, image=${item.image}")
|
||||
item.image?.let { url ->
|
||||
image.visible()
|
||||
Glide
|
||||
.with(image)
|
||||
.load(url)
|
||||
.centerCrop()
|
||||
.into(image)
|
||||
} ?: apply { image.setImageDrawable(null) }
|
||||
loadImageWithCustomResize(image, url)
|
||||
} ?: run { image.setImageDrawable(null) }
|
||||
}
|
||||
|
||||
private fun showKeyboard() {
|
||||
content.postDelayed(16L) {
|
||||
imm().showSoftInput(content, InputMethodManager.SHOW_IMPLICIT)
|
||||
}
|
||||
private fun loadImageWithCustomResize(imageView: ImageView, url: String) {
|
||||
val context = imageView.context
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
val screenWidth = displayMetrics.widthPixels
|
||||
val maxWidth = screenWidth - dpToPx(context, 40)
|
||||
val maxHeight = dpToPx(context, 443)
|
||||
|
||||
Glide.with(context)
|
||||
.load(url)
|
||||
.override(Target.SIZE_ORIGINAL)
|
||||
.apply(RequestOptions().transform(CustomImageResizeTransformation(maxWidth, maxHeight)))
|
||||
.into(imageView)
|
||||
}
|
||||
|
||||
private fun dpToPx(context: Context, dp: Int): Int {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
dp.toFloat(),
|
||||
context.resources.displayMetrics
|
||||
).toInt()
|
||||
}
|
||||
|
||||
open fun processPayloads(
|
||||
|
@ -275,14 +296,25 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
fun bind(
|
||||
item: BlockView.Title.Basic,
|
||||
onPageIconClicked: () -> Unit,
|
||||
onCoverClicked: () -> Unit
|
||||
onCoverClicked: () -> Unit,
|
||||
click: (ListenerType) -> Unit
|
||||
) {
|
||||
super.bind(
|
||||
item = item,
|
||||
onCoverClicked = onCoverClicked
|
||||
onCoverClicked = onCoverClicked,
|
||||
click = click
|
||||
)
|
||||
setEmoji(item)
|
||||
applySearchHighlights(item)
|
||||
|
||||
image.setOnClickListener {
|
||||
click(
|
||||
ListenerType.Picture.TitleView(
|
||||
item = item
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (item.mode == BlockView.Mode.EDIT) {
|
||||
icon.setOnClickListener { onPageIconClicked() }
|
||||
image.setOnClickListener { onPageIconClicked() }
|
||||
|
@ -299,9 +331,11 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
topMargin = dimen(R.dimen.dp_10)
|
||||
}
|
||||
binding.imageIcon.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
topMargin = if (!item.hasCover) dimen(R.dimen.dp_51) else dimen(R.dimen.dp_102)
|
||||
topMargin =
|
||||
if (!item.hasCover) dimen(R.dimen.dp_51) else dimen(R.dimen.dp_102)
|
||||
}
|
||||
}
|
||||
|
||||
item.emoji != null -> {
|
||||
binding.imageIcon.gone()
|
||||
binding.docEmojiIconContainer.visible()
|
||||
|
@ -309,9 +343,11 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
topMargin = dimen(R.dimen.dp_12)
|
||||
}
|
||||
binding.docEmojiIconContainer.updateLayoutParams<ConstraintLayout.LayoutParams> {
|
||||
topMargin = if (!item.hasCover) dimen(R.dimen.dp_60) else dimen(R.dimen.dp_120)
|
||||
topMargin =
|
||||
if (!item.hasCover) dimen(R.dimen.dp_60) else dimen(R.dimen.dp_120)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
binding.imageIcon.gone()
|
||||
binding.docEmojiIconContainer.gone()
|
||||
|
@ -397,9 +433,10 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
override val content: TextInputWidget = binding.title
|
||||
override val selectionView: View = itemView
|
||||
|
||||
private val gradientView : ComposeView get() = binding
|
||||
.docProfileIconContainer
|
||||
.findViewById(R.id.gradient)
|
||||
private val gradientView: ComposeView
|
||||
get() = binding
|
||||
.docProfileIconContainer
|
||||
.findViewById(R.id.gradient)
|
||||
|
||||
private val iconText = binding.imageText
|
||||
private var hasImage = false
|
||||
|
@ -411,11 +448,13 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
fun bind(
|
||||
item: BlockView.Title.Profile,
|
||||
onProfileIconClicked: (ListenerType) -> Unit,
|
||||
onCoverClicked: () -> Unit
|
||||
onCoverClicked: () -> Unit,
|
||||
click: (ListenerType) -> Unit
|
||||
) {
|
||||
super.bind(
|
||||
item = item,
|
||||
onCoverClicked = onCoverClicked
|
||||
onCoverClicked = onCoverClicked,
|
||||
click = click
|
||||
)
|
||||
setupMargins(item)
|
||||
applySearchHighlights(item)
|
||||
|
@ -512,11 +551,13 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
fun bind(
|
||||
item: BlockView.Title.Todo,
|
||||
onPageIconClicked: () -> Unit,
|
||||
onCoverClicked: () -> Unit
|
||||
onCoverClicked: () -> Unit,
|
||||
click: (ListenerType) -> Unit
|
||||
) {
|
||||
super.bind(
|
||||
item = item,
|
||||
onCoverClicked = onCoverClicked
|
||||
onCoverClicked = onCoverClicked,
|
||||
click = click
|
||||
)
|
||||
setLocked(item.mode)
|
||||
checkbox.isSelected = item.isChecked
|
||||
|
@ -576,7 +617,8 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
|
|||
) {
|
||||
super.bind(
|
||||
item = item,
|
||||
onCoverClicked = {}
|
||||
onCoverClicked = {},
|
||||
click = {}
|
||||
)
|
||||
icon.setIcon(item.icon)
|
||||
}
|
||||
|
|
|
@ -392,4 +392,4 @@ class ObjectIconWidget @JvmOverloads constructor(
|
|||
this.width = emojiSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,21 +52,24 @@
|
|||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/imageIcon"
|
||||
android:layout_width="108dp"
|
||||
android:layout_height="108dp"
|
||||
tools:src="@drawable/a123"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxHeight="443dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginStart="15dp"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:layout_marginTop="51dp"
|
||||
android:adjustViewBounds="true"
|
||||
android:background="@color/shape_tertiary"
|
||||
android:padding="4dp"
|
||||
android:transitionName="@string/logo_transition"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:shapeAppearance="@style/TitleImageAppearanceOverlay"
|
||||
app:strokeColor="@color/background_primary"
|
||||
app:strokeWidth="4dp"
|
||||
tools:visibility="gone" />
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
|
||||
android:id="@+id/title"
|
||||
|
@ -76,7 +79,7 @@
|
|||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
app:ignoreDragAndDrop="true"
|
||||
android:layout_marginTop="@dimen/dp_32"
|
||||
android:layout_marginTop="@dimen/dp_16"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/barrier"
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
android:layout_marginStart="28dp"
|
||||
android:layout_marginTop="80dp"
|
||||
app:imageSize="80dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
tools:src="@drawable/ic_mime_pdf"
|
||||
android:background="@drawable/bg_title_file_icon"
|
||||
android:transitionName="@string/logo_transition"
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<dimen name="dp_102">102dp</dimen>
|
||||
<dimen name="dp_120">120dp</dimen>
|
||||
<dimen name="dp_203">203dp</dimen>
|
||||
<dimen name="dp_443">443dp</dimen>
|
||||
|
||||
<dimen name="roundedTextBorderRadius">4dp</dimen>
|
||||
<dimen name="roundedTextBorderWidth">1dp</dimen>
|
||||
|
|
|
@ -47,6 +47,11 @@ interface UserSettingsCache {
|
|||
suspend fun getAllContentSort(space: SpaceId): Pair<Id, Boolean>?
|
||||
suspend fun setAllContentSort(space: SpaceId, sort: Id, isAsc: Boolean)
|
||||
|
||||
suspend fun setTooltipShown(shown: Boolean)
|
||||
suspend fun isTooltipShown(): Boolean
|
||||
suspend fun setSpaceSwitchCount(count: Int)
|
||||
suspend fun getSpaceSwitchCount(): Int
|
||||
|
||||
suspend fun setRelativeDates(account: Account, enabled: Boolean)
|
||||
suspend fun setDateFormat(account: Account, format: String)
|
||||
|
||||
|
|
|
@ -570,6 +570,22 @@ class DefaultUserSettingsCache(
|
|||
}
|
||||
}
|
||||
|
||||
override suspend fun setTooltipShown(shown: Boolean) {
|
||||
prefs.edit().putBoolean(TOOLTIP_SHOWN_KEY, shown).apply()
|
||||
}
|
||||
|
||||
override suspend fun isTooltipShown(): Boolean {
|
||||
return prefs.getBoolean(TOOLTIP_SHOWN_KEY, false)
|
||||
}
|
||||
|
||||
override suspend fun setSpaceSwitchCount(count: Int) {
|
||||
prefs.edit().putInt(SPACE_SWITCH_COUNT_KEY, count).apply()
|
||||
}
|
||||
|
||||
override suspend fun getSpaceSwitchCount(): Int {
|
||||
return prefs.getInt(SPACE_SWITCH_COUNT_KEY, 0)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val CURRENT_SPACE_KEY = "prefs.user_settings.current_space"
|
||||
const val DEFAULT_OBJECT_TYPE_ID_KEY = "prefs.user_settings.default_object_type.id"
|
||||
|
@ -585,5 +601,8 @@ class DefaultUserSettingsCache(
|
|||
|
||||
const val COLLAPSED_WIDGETS_KEY = "prefs.user_settings.collapsed-widgets"
|
||||
const val ACTIVE_WIDGETS_VIEWS_KEY = "prefs.user_settings.active-widget-views"
|
||||
|
||||
const val TOOLTIP_SHOWN_KEY = "tooltip_shown_key"
|
||||
const val SPACE_SWITCH_COUNT_KEY = "space_switch_count_key"
|
||||
}
|
||||
}
|
|
@ -3843,6 +3843,25 @@ class EditorViewModel(
|
|||
else -> Unit
|
||||
}
|
||||
}
|
||||
is ListenerType.Picture.TitleView -> {
|
||||
when (mode) {
|
||||
EditorMode.Edit, EditorMode.Locked, EditorMode.Read -> {
|
||||
if (!clicked.item.image.isNullOrEmpty()){
|
||||
dispatch(
|
||||
Command.OpenFullScreenImage(
|
||||
target = "",
|
||||
url = clicked.item.image
|
||||
)
|
||||
)
|
||||
} else {
|
||||
Timber.e("Block is not File or with wrong state, can't proceed with download")
|
||||
sendToast("Something went wrong. Couldn't open image")
|
||||
}
|
||||
}
|
||||
EditorMode.Select -> onBlockMultiSelectClicked(clicked.item.id)
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
is ListenerType.Picture.View -> {
|
||||
when (mode) {
|
||||
EditorMode.Edit, EditorMode.Locked, EditorMode.Read -> {
|
||||
|
|
|
@ -23,6 +23,7 @@ sealed interface ListenerType {
|
|||
}
|
||||
|
||||
sealed class Picture: ListenerType {
|
||||
data class TitleView(val item: BlockView.Title.Basic) : Picture()
|
||||
data class View(val target: String) : Picture()
|
||||
data class Placeholder(val target: String) : Picture()
|
||||
data class Upload(val target: String) : Picture()
|
||||
|
|
|
@ -1516,7 +1516,7 @@ class DefaultBlockViewRenderer @Inject constructor(
|
|||
text = fieldParser.getObjectName(currentObject),
|
||||
image = currentObject.iconImage?.let { image ->
|
||||
if (image.isNotBlank())
|
||||
urlBuilder.thumbnail(image)
|
||||
urlBuilder.original(image)
|
||||
else
|
||||
null
|
||||
},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue