1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

DROID-492 Set | Fix | Fix cover image in set and in sets gallery mode (#2713)

This commit is contained in:
Mikhail 2022-11-22 18:08:03 +03:00 committed by GitHub
parent 53c3c85f08
commit 779ecb47d5
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 191 additions and 138 deletions

View file

@ -47,6 +47,7 @@ import com.anytypeio.anytype.domain.page.CreateNewObject
import com.anytypeio.anytype.domain.search.CancelSearchSubscription
import com.anytypeio.anytype.domain.search.DataViewSubscriptionContainer
import com.anytypeio.anytype.domain.search.SubscriptionEventChannel
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.sets.ObjectSetDatabase
import com.anytypeio.anytype.presentation.sets.ObjectSetPaginator
import com.anytypeio.anytype.presentation.sets.ObjectSetRecordCache
@ -80,6 +81,9 @@ abstract class TestObjectSetSetup {
lateinit var urlBuilder: UrlBuilder
@Mock
lateinit var coverImageHashProvider: CoverImageHashProvider
@Mock
lateinit var repo: BlockRepository
@ -187,6 +191,7 @@ abstract class TestObjectSetSetup {
setObjectDetails = setObjectDetails,
updateText = updateText,
urlBuilder = urlBuilder,
coverImageHashProvider = coverImageHashProvider,
session = session,
dispatcher = dispatcher,
reducer = reducer,

View file

@ -51,6 +51,7 @@ import com.anytypeio.anytype.domain.unsplash.DownloadUnsplashImage
import com.anytypeio.anytype.domain.unsplash.UnsplashRepository
import com.anytypeio.anytype.presentation.common.Action
import com.anytypeio.anytype.presentation.common.Delegator
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectRelationProvider
import com.anytypeio.anytype.presentation.relations.providers.DataViewObjectValueProvider
import com.anytypeio.anytype.presentation.relations.providers.ObjectDetailProvider
@ -65,7 +66,11 @@ import com.anytypeio.anytype.presentation.sets.ObjectSetReducer
import com.anytypeio.anytype.presentation.sets.ObjectSetSession
import com.anytypeio.anytype.presentation.sets.ObjectSetViewModelFactory
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.presentation.util.downloader.UriFileProvider
import com.anytypeio.anytype.providers.DefaultCoverImageHashProvider
import com.anytypeio.anytype.providers.DefaultUriFileProvider
import com.anytypeio.anytype.ui.sets.ObjectSetFragment
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
@ -115,7 +120,9 @@ interface ObjectSetSubComponent {
fun objectUnsplashComponent(): UnsplashSubComponent.Builder
}
@Module
@Module(
includes = [ObjectSetModule.Bindings::class]
)
object ObjectSetModule {
@JvmStatic
@ -143,6 +150,7 @@ object ObjectSetModule {
delegator: Delegator<Action>,
objectSetRecordCache: ObjectSetRecordCache,
urlBuilder: UrlBuilder,
coverImageHashProvider: CoverImageHashProvider,
session: ObjectSetSession,
analytics: Analytics,
downloadUnsplashImage: DownloadUnsplashImage,
@ -168,6 +176,7 @@ object ObjectSetModule {
dispatcher = dispatcher,
delegator = delegator,
objectSetRecordCache = objectSetRecordCache,
coverImageHashProvider = coverImageHashProvider,
urlBuilder = urlBuilder,
session = session,
analytics = analytics,
@ -465,4 +474,14 @@ object ObjectSetModule {
): DuplicateObject = DuplicateObject(
repo = repo
)
@Module
interface Bindings {
@PerScreen
@Binds
fun bindCoverImageHashProvider(
defaultProvider: DefaultCoverImageHashProvider
): CoverImageHashProvider
}
}

View file

@ -9,5 +9,6 @@ enum class CoverType(val code: Int) {
UPLOADED_IMAGE(1),
COLOR(2),
GRADIENT(3),
BUNDLED_IMAGE(4)
BUNDLED_IMAGE(4),
UNSPLASH_IMAGE(5)
}

View file

@ -5,7 +5,6 @@ import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.extensions.tint
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
import com.anytypeio.anytype.presentation.editor.cover.CoverGradient
import com.anytypeio.anytype.presentation.editor.cover.CoverView
import com.bumptech.glide.Glide
@ -23,11 +22,8 @@ class GalleryCoverWidget @JvmOverloads constructor(
when (cover) {
is CoverView.Color -> {
setImageDrawable(null)
val value = CoverColor.values().find { it.code == cover.color }
if (value != null) {
setBackgroundResource(R.drawable.cover_solid_shape_rounded)
tint(value.color)
}
setBackgroundResource(R.drawable.cover_solid_shape_rounded)
tint(cover.coverColor.color)
}
is CoverView.Gradient -> {
setImageDrawable(null)

View file

@ -1,7 +1,7 @@
package com.anytypeio.anytype.presentation.editor.cover
sealed class CoverView {
data class Color(val color: String) : CoverView()
data class Color(val coverColor: CoverColor) : CoverView()
data class Gradient(val gradient: String) : CoverView()
data class Image(val url: String) : CoverView()
}

View file

@ -34,7 +34,11 @@ import com.anytypeio.anytype.presentation.mapper.toVideoView
import com.anytypeio.anytype.presentation.mapper.toView
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.objects.appearance.LinkAppearanceFactory
import com.anytypeio.anytype.presentation.relations.BasicObjectCoverWrapper
import com.anytypeio.anytype.presentation.relations.BlockFieldsCoverWrapper
import com.anytypeio.anytype.presentation.relations.CoverWrapper
import com.anytypeio.anytype.presentation.relations.DocumentRelationView
import com.anytypeio.anytype.presentation.relations.getCover
import com.anytypeio.anytype.presentation.relations.view
import timber.log.Timber
import javax.inject.Inject
@ -1455,32 +1459,8 @@ class DefaultBlockViewRenderer @Inject constructor(
check(rootContent is Content.Smart)
var coverColor: CoverColor? = null
var coverImage: Url? = null
var coverGradient: String? = null
when (val type = rootDetails?.coverType?.toInt()) {
CoverType.UPLOADED_IMAGE.code -> {
coverImage = rootDetails.coverId?.let { id ->
urlBuilder.image(id)
}
}
CoverType.BUNDLED_IMAGE.code -> {
val hash = rootDetails.coverId?.let { id ->
coverImageHashProvider.provide(id)
}
if (hash != null) coverImage = urlBuilder.image(hash)
}
CoverType.COLOR.code -> {
coverColor = rootDetails.coverId?.let { id ->
CoverColor.values().find { it.code == id }
}
}
CoverType.GRADIENT.code -> {
coverGradient = rootDetails.coverId
}
else -> Timber.d("Missing cover type: $type")
}
val coverContainer = BlockFieldsCoverWrapper(rootDetails)
.getCover(urlBuilder, coverImageHashProvider)
val layoutCode = details.details[root.id]?.layout?.toInt()
@ -1519,9 +1499,9 @@ class DefaultBlockViewRenderer @Inject constructor(
},
isFocused = block.id == focus.id,
cursor = cursor,
coverColor = coverColor,
coverImage = coverImage,
coverGradient = coverGradient,
coverColor = coverContainer.coverColor,
coverImage = coverContainer.coverImage,
coverGradient = coverContainer.coverGradient,
background = block.parseThemeBackgroundColor(),
color = block.textColor()
)
@ -1533,9 +1513,9 @@ class DefaultBlockViewRenderer @Inject constructor(
text = content.text,
isFocused = block.id == focus.id,
cursor = cursor,
coverColor = coverColor,
coverImage = coverImage,
coverGradient = coverGradient,
coverColor = coverContainer.coverColor,
coverImage = coverContainer.coverImage,
coverGradient = coverContainer.coverGradient,
isChecked = content.isChecked == true,
background = block.parseThemeBackgroundColor(),
color = block.textColor()
@ -1554,9 +1534,9 @@ class DefaultBlockViewRenderer @Inject constructor(
},
isFocused = block.id == focus.id,
cursor = cursor,
coverColor = coverColor,
coverImage = coverImage,
coverGradient = coverGradient,
coverColor = coverContainer.coverColor,
coverImage = coverContainer.coverImage,
coverGradient = coverContainer.coverGradient,
background = block.parseThemeBackgroundColor(),
color = block.textColor()
)
@ -1577,9 +1557,9 @@ class DefaultBlockViewRenderer @Inject constructor(
},
isFocused = block.id == focus.id,
cursor = cursor,
coverColor = coverColor,
coverImage = coverImage,
coverGradient = coverGradient,
coverColor = coverContainer.coverColor,
coverImage = coverContainer.coverImage,
coverGradient = coverContainer.coverGradient,
background = block.parseThemeBackgroundColor(),
color = block.textColor()
)
@ -1739,47 +1719,19 @@ class DefaultBlockViewRenderer @Inject constructor(
obj: ObjectWrapper.Basic,
urlBuilder: UrlBuilder
): BlockView.LinkToObject.Default.Card.Cover? {
return when (obj.coverType) {
CoverType.UPLOADED_IMAGE -> {
val url = obj.coverId?.let { id -> urlBuilder.image(id) }
if (url != null) {
BlockView.LinkToObject.Default.Card.Cover.Image(url = url)
} else {
null
}
}
CoverType.BUNDLED_IMAGE -> {
val hash = obj.coverId?.let { id ->
coverImageHashProvider.provide(id)
}
if (hash != null) {
BlockView.LinkToObject.Default.Card.Cover.Image(url = urlBuilder.image(hash))
} else {
null
}
}
CoverType.COLOR -> {
val coverColor = obj.coverId?.let { id ->
CoverColor.values().find { it.code == id }
}
if (coverColor != null) {
BlockView.LinkToObject.Default.Card.Cover.Color(color = coverColor)
} else {
null
}
}
CoverType.GRADIENT -> {
val coverGradient = obj.coverId
if (coverGradient != null) {
BlockView.LinkToObject.Default.Card.Cover.Gradient(
gradient = coverGradient
)
} else {
null
}
}
else -> null
}
val coverContainer =
BasicObjectCoverWrapper(obj).getCover(urlBuilder, coverImageHashProvider)
if (coverContainer.coverImage != null)
return BlockView.LinkToObject.Default.Card.Cover.Image(coverContainer.coverImage)
if (coverContainer.coverGradient != null)
return BlockView.LinkToObject.Default.Card.Cover.Gradient(coverContainer.coverGradient)
if (coverContainer.coverColor != null)
return BlockView.LinkToObject.Default.Card.Cover.Color(coverContainer.coverColor)
return null
}
private fun linkToObjectCard(
@ -2054,7 +2006,7 @@ class DefaultBlockViewRenderer @Inject constructor(
null
}
} else {
null
null
}
cells.add(
BlockView.Table.Cell(

View file

@ -0,0 +1,81 @@
package com.anytypeio.anytype.presentation.relations
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.CoverType
import com.anytypeio.anytype.core_models.ObjectWrapper
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.BuildConfig
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import timber.log.Timber
fun CoverWrapper.getCover(
urlBuilder: UrlBuilder,
coverImageHashProvider: CoverImageHashProvider
): CoverContainer {
val type = coverType ?: return CoverContainer()
var coverColor: CoverColor? = null
var coverImage: Url? = null
var coverGradient: String? = null
when (type) {
CoverType.UPLOADED_IMAGE,
CoverType.UNSPLASH_IMAGE -> {
coverImage = coverId?.let { id ->
urlBuilder.image(id)
}
}
CoverType.BUNDLED_IMAGE -> {
val hash = coverId?.let { id ->
coverImageHashProvider.provide(id)
}
if (hash != null) coverImage = urlBuilder.image(hash)
}
CoverType.COLOR -> {
coverColor = coverId?.let { id ->
CoverColor.values().find { it.code == id }
}
}
CoverType.GRADIENT -> {
coverGradient = coverId
}
else -> {
Timber.d("Missing cover type: $type")
if (BuildConfig.DEBUG) {
throw IllegalStateException("Missing cover type: $type")
}
}
}
return CoverContainer(coverColor, coverImage, coverGradient)
}
class CoverContainer(
val coverColor: CoverColor? = null,
val coverImage: Url? = null,
val coverGradient: String? = null
)
interface CoverWrapper {
val coverType: CoverType?
val coverId: String?
}
class BlockFieldsCoverWrapper(val fields: Block.Fields?) : CoverWrapper {
override val coverType: CoverType?
get() {
val value = fields?.coverType?.toInt() ?: return null
return CoverType.values().find { type -> type.code == value }
}
override val coverId = fields?.coverId
}
class BasicObjectCoverWrapper(val obj: ObjectWrapper.Basic?) : CoverWrapper {
override val coverType = obj?.coverType
override val coverId = obj?.coverId
}

View file

@ -30,6 +30,7 @@ import com.anytypeio.anytype.core_utils.ext.YESTERDAY
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.ObjectStore
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.extension.isValueRequired
import com.anytypeio.anytype.presentation.mapper.toCheckboxView
@ -81,13 +82,14 @@ fun DV.tabs(activeViewerId: String? = null): List<ViewerTabView> {
suspend fun DVViewer.render(
builder: UrlBuilder,
coverImageHashProvider: CoverImageHashProvider,
useFallbackView: Boolean = false,
objects: List<Id>,
details: Map<Id, Block.Fields>,
dataViewRelations: List<Relation>,
store: ObjectStore
): ObjectSetViewState {
return when(type) {
return when (type) {
DVViewerType.GRID -> {
buildGridView(
dataViewRelations = dataViewRelations,
@ -105,6 +107,7 @@ suspend fun DVViewer.render(
objects = objects,
details = details,
relations = dataViewRelations,
coverImageHashProvider = coverImageHashProvider,
urlBuilder = builder,
store = store
),
@ -196,33 +199,14 @@ private suspend fun DVViewer.buildGridView(
fun title(
title: Block,
ctx: Id,
coverImageHashProvider: CoverImageHashProvider,
urlBuilder: UrlBuilder,
details: Map<Id, Block.Fields>
): BlockView.Title.Basic {
val objectDetails = details[ctx]
var coverColor: CoverColor? = null
var coverImage: Url? = null
var coverGradient: String? = null
when (val type = objectDetails?.coverType?.toInt()) {
CoverType.UPLOADED_IMAGE.code -> {
coverImage = objectDetails.coverId?.let { id ->
urlBuilder.image(id)
}
}
CoverType.COLOR.code -> {
coverColor = objectDetails.coverId?.let { id ->
CoverColor.values().find { it.code == id }
}
}
CoverType.GRADIENT.code -> {
coverGradient = objectDetails.coverId
}
else -> Timber.d("Missing cover type: $type")
}
val coverContainer = BlockFieldsCoverWrapper(objectDetails)
.getCover(urlBuilder, coverImageHashProvider)
return BlockView.Title.Basic(
id = title.id,
@ -234,9 +218,9 @@ fun title(
else
null
},
coverImage = coverImage,
coverColor = coverColor,
coverGradient = coverGradient
coverImage = coverContainer.coverImage,
coverColor = coverContainer.coverColor,
coverGradient = coverContainer.coverGradient
)
}

View file

@ -1,24 +1,35 @@
package com.anytypeio.anytype.presentation.sets
import com.anytypeio.anytype.core_models.*
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.DVViewer
import com.anytypeio.anytype.core_models.DVViewerCardSize
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Relation
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_utils.ext.typeOf
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.objects.ObjectStore
import com.anytypeio.anytype.presentation.editor.cover.CoverColor
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.editor.cover.CoverView
import com.anytypeio.anytype.presentation.objects.ObjectIcon
import com.anytypeio.anytype.presentation.objects.getProperName
import com.anytypeio.anytype.presentation.objects.values
import com.anytypeio.anytype.presentation.relations.BasicObjectCoverWrapper
import com.anytypeio.anytype.presentation.relations.getCover
import com.anytypeio.anytype.presentation.sets.model.Viewer
import timber.log.Timber
suspend fun DVViewer.buildGalleryViews(
objects: List<Id>,
relations: List<Relation>,
details: Map<Id, Block.Fields>,
coverImageHashProvider: CoverImageHashProvider,
urlBuilder: UrlBuilder,
store: ObjectStore
) : List<Viewer.GalleryView.Item> {
): List<Viewer.GalleryView.Item> {
val filteredRelations = viewerRelations.mapNotNull { setting ->
if (setting.isVisible && setting.key != Relations.NAME) {
relations.find { it.key == setting.key }
@ -27,7 +38,7 @@ suspend fun DVViewer.buildGalleryViews(
}
}
return objects.mapNotNull { id -> store.get(id) }.map { obj ->
if (coverRelationKey == null) {
if (obj.coverType == null && coverRelationKey == null) {
Viewer.GalleryView.Item.Default(
objectId = obj.id,
relations = obj.values(
@ -47,31 +58,23 @@ suspend fun DVViewer.buildGalleryViews(
)
} else {
var cover : CoverView? = null
var cover: CoverView? = null
var coverColor: String? = null
var coverColor: CoverColor? = null
var coverImage: Url? = null
var coverGradient: String? = null
if (coverRelationKey == Relations.PAGE_COVER) {
when (obj.coverType?.code) {
CoverType.UPLOADED_IMAGE.code -> {
coverImage = obj.coverId?.let { id ->
urlBuilder.image(id)
}
}
CoverType.COLOR.code -> {
coverColor = obj.coverId
}
CoverType.GRADIENT.code -> {
coverGradient = obj.coverId
}
else -> Timber.d("Missing cover type: $type")
}
if (obj.coverType != null ) {
val coverContainer = BasicObjectCoverWrapper(obj)
.getCover(urlBuilder, coverImageHashProvider)
coverColor = coverContainer.coverColor
coverImage = coverContainer.coverImage
coverGradient = coverContainer.coverGradient
} else {
val previewRelation = relations.find { it.key == coverRelationKey }
if (previewRelation != null && previewRelation.format == Relation.Format.FILE) {
val ids : List<Id> = when(val value = obj.map[previewRelation.key]) {
val ids: List<Id> = when (val value = obj.map[previewRelation.key]) {
is Id -> listOf(value)
is List<*> -> value.typeOf()
else -> emptyList()

View file

@ -46,6 +46,7 @@ import com.anytypeio.anytype.domain.templates.GetTemplates
import com.anytypeio.anytype.domain.unsplash.DownloadUnsplashImage
import com.anytypeio.anytype.presentation.common.Action
import com.anytypeio.anytype.presentation.common.Delegator
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.editor.editor.Proxy
import com.anytypeio.anytype.presentation.editor.editor.listener.ListenerType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
@ -103,6 +104,7 @@ class ObjectSetViewModel(
private val delegator: Delegator<Action>,
private val objectSetRecordCache: ObjectSetRecordCache,
private val urlBuilder: UrlBuilder,
private val coverImageHashProvider: CoverImageHashProvider,
private val session: ObjectSetSession,
private val analytics: Analytics,
private val getTemplates: GetTemplates,
@ -168,6 +170,7 @@ class ObjectSetViewModel(
_header.value = set.blocks.title()?.let {
title(
ctx = context,
coverImageHashProvider = coverImageHashProvider,
urlBuilder = urlBuilder,
details = set.details,
title = it
@ -227,6 +230,7 @@ class ObjectSetViewModel(
val dv = state.dv
Timber.d("FLOW:: Rendering")
(dv.viewers.find { it.id == view } ?: dv.viewers.firstOrNull())?.render(
coverImageHashProvider = coverImageHashProvider,
builder = urlBuilder,
objects = db.objects,
dataViewRelations = dv.relations,

View file

@ -23,6 +23,7 @@ import com.anytypeio.anytype.presentation.common.Delegator
import com.anytypeio.anytype.domain.page.CreateNewObject
import com.anytypeio.anytype.domain.search.CancelSearchSubscription
import com.anytypeio.anytype.domain.search.DataViewSubscriptionContainer
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.util.Dispatcher
class ObjectSetViewModelFactory(
@ -41,6 +42,7 @@ class ObjectSetViewModelFactory(
private val dispatcher: Dispatcher<Payload>,
private val delegator: Delegator<Action>,
private val objectSetRecordCache: ObjectSetRecordCache,
private val coverImageHashProvider: CoverImageHashProvider,
private val urlBuilder: UrlBuilder,
private val session: ObjectSetSession,
private val analytics: Analytics,
@ -70,6 +72,7 @@ class ObjectSetViewModelFactory(
dispatcher = dispatcher,
delegator = delegator,
objectSetRecordCache = objectSetRecordCache,
coverImageHashProvider = coverImageHashProvider,
urlBuilder = urlBuilder,
session = session,
analytics = analytics,

View file

@ -43,6 +43,7 @@ import com.anytypeio.anytype.domain.templates.GetTemplates
import com.anytypeio.anytype.domain.unsplash.DownloadUnsplashImage
import com.anytypeio.anytype.presentation.common.Action
import com.anytypeio.anytype.presentation.common.Delegator
import com.anytypeio.anytype.presentation.editor.cover.CoverImageHashProvider
import com.anytypeio.anytype.presentation.sets.ObjectSetDatabase
import com.anytypeio.anytype.presentation.sets.ObjectSetPaginator
import com.anytypeio.anytype.presentation.sets.ObjectSetRecordCache
@ -120,6 +121,9 @@ open class ObjectSetViewModelTestSetup {
@Mock
lateinit var repo: BlockRepository
@Mock
lateinit var coverImageHashProvider: CoverImageHashProvider
@Mock
lateinit var subscriptionEventChannel: SubscriptionEventChannel
@ -163,6 +167,7 @@ open class ObjectSetViewModelTestSetup {
delegator = delegator,
reducer = reducer,
objectSetRecordCache = cache,
coverImageHashProvider = coverImageHashProvider,
urlBuilder = urlBuilder,
session = session,
analytics = analytics,
@ -259,7 +264,7 @@ open class ObjectSetViewModelTestSetup {
fun stubGetTemplates(
type: String,
templates : List<Id> = emptyList()
templates: List<Id> = emptyList()
) {
getTemplates.stub {
onBlocking {