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

Dashboard | Object icon refactoring (#1673)

This commit is contained in:
Evgenii Kozlov 2021-07-25 11:37:07 +03:00 committed by GitHub
parent c15d2485c8
commit c3fab7349b
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 314 additions and 212 deletions

3
.gitignore vendored
View file

@ -3,6 +3,7 @@
/local.properties
/configuration.properties
/github.properties
/apikeys.properties
.idea/*
!.idea/copyright
.DS_Store
@ -11,4 +12,4 @@
/captures
.externalNativeBuild
ktlint
.idea/*.xml
.idea/*.xml

View file

@ -21,6 +21,8 @@ import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.config.Gateway
import com.anytypeio.anytype.domain.dataview.interactor.ObjectRelationList
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.relations.AddToFeaturedRelations
import com.anytypeio.anytype.domain.relations.RemoveFromFeaturedRelations
import com.anytypeio.anytype.mocking.MockDataFactory
import com.anytypeio.anytype.presentation.page.Editor
import com.anytypeio.anytype.presentation.page.editor.DetailModificationManager
@ -64,6 +66,8 @@ class ObjectRelationListTest {
private lateinit var objectRelationList: ObjectRelationList
private lateinit var updateDetail: UpdateDetail
private lateinit var addToFeaturedRelations: AddToFeaturedRelations
private lateinit var removeFromFeaturedRelations: RemoveFromFeaturedRelations
private val ctx = MockDataFactory.randomUuid()
private val storage = Editor.Storage()
@ -76,13 +80,17 @@ class ObjectRelationListTest {
urlBuilder = UrlBuilder(gateway)
objectRelationList = ObjectRelationList(repo)
updateDetail = UpdateDetail(repo)
addToFeaturedRelations = AddToFeaturedRelations(repo)
removeFromFeaturedRelations = RemoveFromFeaturedRelations(repo)
TestRelationListFragment.testVmFactory = ObjectRelationListViewModelFactory(
stores = storage,
urlBuilder = urlBuilder,
objectRelationList = objectRelationList,
dispatcher = dispatcher,
detailModificationManager = detailModificationManager,
updateDetail = updateDetail
updateDetail = updateDetail,
addToFeaturedRelations = addToFeaturedRelations,
removeFromFeaturedRelations = removeFromFeaturedRelations
)
}

View file

@ -60,7 +60,8 @@ object HomeDashboardModule {
searchRecentObjects: SearchRecentObjects,
searchInboxObjects: SearchInboxObjects,
searchObjectSets: SearchObjectSets,
getFlavourConfig: GetFlavourConfig
getFlavourConfig: GetFlavourConfig,
urlBuilder: UrlBuilder
): HomeDashboardViewModelFactory = HomeDashboardViewModelFactory(
getProfile = getProfile,
openDashboard = openDashboard,
@ -76,7 +77,8 @@ object HomeDashboardModule {
searchInboxObjects = searchInboxObjects,
searchObjectSets = searchObjectSets,
analytics = analytics,
getFlavourConfig = getFlavourConfig
getFlavourConfig = getFlavourConfig,
urlBuilder = urlBuilder
)
@JvmStatic

View file

@ -15,10 +15,8 @@ import com.anytypeio.anytype.core_utils.ext.invisible
import com.anytypeio.anytype.core_utils.ext.shift
import com.anytypeio.anytype.core_utils.ext.typeOf
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.emojifier.Emojifier
import com.anytypeio.anytype.presentation.`object`.ObjectIcon
import com.anytypeio.anytype.presentation.desktop.DashboardView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.facebook.shimmer.ShimmerFrameLayout
import kotlinx.android.synthetic.main.item_dashboard_card_default.view.*
import kotlinx.android.synthetic.main.item_desktop_archive.view.*
@ -137,8 +135,7 @@ class DashboardAdapter(
with(holder) {
bindTitle(item.title)
bindSubtitle(item.typeName)
bindEmoji(item.emoji)
bindImage(item.image, item.layout, item.title)
bindIcon(item.icon)
bindLoading(item.isLoading)
}
}
@ -159,7 +156,7 @@ class DashboardAdapter(
with(holder) {
val item = data[position] as DashboardView.ObjectSet
bindTitle(item.title)
bindEmoji(item.emoji)
bindIcon(item.icon)
bindLoading(item.isLoading)
}
}
@ -217,10 +214,10 @@ class DashboardAdapter(
bindTitle(item.title)
}
if (payload.emojiChanged()) {
bindEmoji(item.emoji)
bindIcon(item.icon)
}
if (payload.imageChanged()) {
bindImage(item.image, item.layout, item.title)
bindIcon(item.icon)
}
if (payload.isLoadingChanged) {
bindLoading(item.isLoading)
@ -259,10 +256,6 @@ class DashboardAdapter(
private val tvTitle = itemView.title
private val tvSubtitle = itemView.typeTitle
private val ivEmoji = itemView.emojiIcon
private val circleImage = itemView.circleImage
private val rectangleImage = itemView.rectangleImage
private val avatar = itemView.avatar
private val shimmer = itemView.shimmer
fun bindTitle(title: String?) {
@ -276,6 +269,10 @@ class DashboardAdapter(
tvSubtitle.text = subtitle
}
fun bindIcon(icon: ObjectIcon) {
itemView.iconWidget.bind(icon)
}
fun bindLoading(isLoading: Boolean) {
if (isLoading) {
tvTitle.invisible()
@ -287,65 +284,6 @@ class DashboardAdapter(
tvTitle.visible()
}
}
fun bindEmoji(emoji: String?) {
try {
emoji?.let { unicode ->
Glide
.with(ivEmoji)
.load(Emojifier.uri(unicode))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivEmoji)
} ?: run {
ivEmoji.setImageDrawable(null)
}
} catch (e: Throwable) {
Timber.e(e, "Could not set emoji icon")
}
}
fun bindImage(
image: String?,
layout: ObjectType.Layout?,
name: String?
) {
when (layout) {
ObjectType.Layout.BASIC -> bindRectangleImage(image)
ObjectType.Layout.PROFILE -> {
if (image != null) {
avatar.invisible()
bindCircleImage(image)
} else {
rectangleImage.invisible()
avatar.visible()
avatar.bind(name.orEmpty())
}
}
else -> Timber.d("Skipping image bound")
}
}
private fun bindCircleImage(image: String?) {
image?.let { url ->
Glide
.with(circleImage)
.load(url)
.centerInside()
.circleCrop()
.into(circleImage)
} ?: run { circleImage.setImageDrawable(null) }
}
private fun bindRectangleImage(image: String?) {
Timber.d("Binding rectangle image: $image")
image?.let { url ->
Glide
.with(rectangleImage)
.load(url)
.centerCrop()
.into(rectangleImage)
} ?: run { rectangleImage.setImageDrawable(null) }
}
}
class DocumentWithoutIconViewHolder(parent: ViewGroup) : ViewHolder(
@ -430,7 +368,6 @@ class DashboardAdapter(
class ObjectSetHolder(itemView: View) : ViewHolder(itemView) {
private val tvTitle = itemView.title
private val ivEmoji = itemView.emojiIcon
private val shimmer = itemView.shimmer
fun bindLoading(isLoading: Boolean) {
@ -452,18 +389,8 @@ class DashboardAdapter(
tvTitle.text = title
}
fun bindEmoji(emoji: String?) {
try {
emoji?.let { unicode ->
Glide
.with(ivEmoji)
.load(Emojifier.uri(unicode))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivEmoji)
}
} catch (e: Throwable) {
Timber.e(e, "Could not set emoji icon")
}
fun bindIcon(icon: ObjectIcon) {
itemView.iconWidget.bind(icon)
}
}
}

View file

@ -8,59 +8,18 @@
android:background="@drawable/ripple_dashboard_card"
app:cardElevation="0dp">
<FrameLayout
android:id="@+id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
<com.anytypeio.anytype.core_ui.widgets.ObjectCardIconWidget
android:id="@+id/iconWidget"
android:layout_width="@dimen/dashboard_object_icon_default_size"
android:layout_height="@dimen/dashboard_object_icon_default_size"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp">
<androidx.cardview.widget.CardView
android:id="@+id/roundedImageContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="2dp"
app:cardElevation="0dp">
<ImageView
android:id="@+id/rectangleImage"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/emoji"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/emoji_color"
android:visibility="invisible" />
<ImageView
android:id="@+id/emojiIcon"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/circleImage"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.anytypeio.anytype.core_ui.widgets.AvatarWidget
android:id="@+id/avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/circle_solid_default"
android:visibility="invisible"
app:text_size="28sp" />
</FrameLayout>
android:layout_marginTop="16dp"/>
<TextView
android:id="@+id/title"
style="@style/DashboardDocumentTitleStyle"
android:layout_width="match_parent"
android:hint="@string/untitled"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="79dp"

View file

@ -12,7 +12,8 @@
android:id="@+id/tvDocTitle"
style="@style/DashboardDocAlternativeTitleStyle"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_height="wrap_content"
android:hint="@string/untitled"
android:layout_marginStart="16dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="16dp"

View file

@ -37,4 +37,5 @@
<dimen name="single_option_value_bottom_list_margin">32dp</dimen>
<dimen name="multiple_option_value_bottom_list_margin">68dp</dimen>
<dimen name="default_dashboard_card_height">124dp</dimen>
<dimen name="dashboard_object_icon_default_size">48dp</dimen>
</resources>

View file

@ -154,6 +154,7 @@
<item name="android:ellipsize">end</item>
<item name="android:textColor">@color/black</item>
<item name="android:textSize">13sp</item>
<item name="android:maxLines">3</item>
</style>
<style name="DashboardDocumentSubtitleStyle">

View file

@ -0,0 +1,90 @@
package com.anytypeio.anytype.core_ui.widgets
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.emojifier.Emojifier
import com.anytypeio.anytype.presentation.`object`.ObjectIcon
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import kotlinx.android.synthetic.main.widget_object_icon_card.view.*
import timber.log.Timber
class ObjectCardIconWidget @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
private val emojiSize = resources.getDimension(R.dimen.object_icon_card_emoji_size).toInt()
private val rectangleImageRadius = resources.getDimension(R.dimen.object_icon_card_rectangle_image_radius).toInt()
init {
View.inflate(context, R.layout.widget_object_icon_card, this)
}
fun bind(icon: ObjectIcon) {
when(icon) {
is ObjectIcon.Basic.Emoji -> {
setBackgroundResource(R.drawable.rect_object_icon_card_emoji_background)
ivIcon.updateLayoutParams<LayoutParams> {
height = emojiSize
width = emojiSize
}
try {
Glide
.with(this)
.load(Emojifier.uri(icon.unicode))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivIcon)
} catch (e: Throwable) {
Timber.e(e, "Error while setting emoji icon for: ${icon.unicode}")
}
}
is ObjectIcon.Basic.Image -> {
setBackgroundResource(0)
ivIcon.updateLayoutParams<LayoutParams> {
height = LayoutParams.MATCH_PARENT
width = LayoutParams.MATCH_PARENT
}
Glide
.with(this)
.load(icon.hash)
.transform(
CenterCrop(),
RoundedCorners(rectangleImageRadius)
)
.into(ivIcon)
}
is ObjectIcon.Profile.Avatar -> {
setBackgroundResource(R.drawable.circle_default_avatar_background)
ivIcon.setImageDrawable(null)
tvInitial.text = icon.name.ifEmpty { DEFAULT_INITIAL_CHAR }.first().uppercaseChar().toString()
}
is ObjectIcon.Profile.Image -> {
setBackgroundResource(0)
ivIcon.updateLayoutParams<LayoutParams> {
height = LayoutParams.MATCH_PARENT
width = LayoutParams.MATCH_PARENT
}
Glide
.with(this)
.load(icon.hash)
.centerInside()
.circleCrop()
.into(ivIcon)
}
else -> {
// TODO
}
}
}
companion object {
const val DEFAULT_INITIAL_CHAR = "U"
}
}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#DFDDD0" />
</shape>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="10dp" />
<solid android:color="#F3F2EC" />
</shape>

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<ImageView
android:id="@+id/ivIcon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:contentDescription="@string/content_description_page_icon" />
<TextView
android:id="@+id/tvInitial"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="@font/inter_semibold"
android:maxLines="1"
android:singleLine="true"
android:textColor="@color/white"
android:textSize="28sp"
tools:text="U" />
</merge>

View file

@ -156,5 +156,7 @@
<dimen name="slash_widget_item_height">55dp</dimen>
<dimen name="data_view_divider_height">0.5dp</dimen>
<dimen name="object_icon_card_emoji_size">28dp</dimen>
<dimen name="object_icon_card_rectangle_image_radius">2dp</dimen>
</resources>

View file

@ -3,6 +3,7 @@ package com.anytypeio.anytype.presentation.desktop
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.presentation.`object`.ObjectIcon
sealed class DashboardView {
@ -29,7 +30,8 @@ sealed class DashboardView {
val type: String? = null,
val done: Boolean? = null,
override val isArchived: Boolean,
override val isLoading: Boolean = false
override val isLoading: Boolean = false,
val icon: ObjectIcon = ObjectIcon.None
) : DashboardView() {
val hasIcon = emoji != null || image != null
}
@ -46,8 +48,8 @@ sealed class DashboardView {
override val id: Id,
val target: Id,
val title: String? = null,
val emoji: String? = null,
override val isArchived: Boolean,
override val isLoading: Boolean = false
override val isLoading: Boolean = false,
val icon: ObjectIcon = ObjectIcon.None
) : DashboardView()
}

View file

@ -23,8 +23,10 @@ import com.anytypeio.anytype.domain.config.GetDebugSettings
import com.anytypeio.anytype.domain.config.GetFlavourConfig
import com.anytypeio.anytype.domain.dashboard.interactor.*
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.page.CreatePage
import com.anytypeio.anytype.presentation.BuildConfig
import com.anytypeio.anytype.presentation.`object`.ObjectIcon
import com.anytypeio.anytype.presentation.desktop.HomeDashboardStateMachine.Interactor
import com.anytypeio.anytype.presentation.desktop.HomeDashboardStateMachine.State
import com.anytypeio.anytype.presentation.mapper.toView
@ -52,7 +54,8 @@ class HomeDashboardViewModel(
private val searchRecentObjects: SearchRecentObjects,
private val searchInboxObjects: SearchInboxObjects,
private val searchObjectSets: SearchObjectSets,
private val getFlavourConfig: GetFlavourConfig
private val getFlavourConfig: GetFlavourConfig,
private val urlBuilder: UrlBuilder
) : ViewStateViewModel<State>(),
HomeDashboardEventConverter by eventConverter,
SupportNavigation<EventWrapper<AppNavigation.Command>> {
@ -394,8 +397,9 @@ class HomeDashboardViewModel(
archived.value = objects
.map { ObjectWrapper.Basic(it) }
.mapNotNull { obj ->
val layout = obj.layout
val oType = stateData.value?.findOTypeById(obj.type)
if (oType?.layout == ObjectType.Layout.SET && !isDataViewEnabled.value) {
if (layout == ObjectType.Layout.SET && !isDataViewEnabled.value) {
null
} else {
DashboardView.Document(
@ -409,7 +413,12 @@ class HomeDashboardViewModel(
type = obj.type.firstOrNull(),
typeName = oType?.name,
layout = obj.layout,
done = obj.done
done = obj.done,
icon = ObjectIcon.from(
obj = obj,
layout = layout,
builder = urlBuilder
)
)
}
}
@ -428,7 +437,8 @@ class HomeDashboardViewModel(
.map { ObjectWrapper.Basic(it) }
.mapNotNull { obj ->
val oType = stateData.value?.findOTypeById(obj.type)
if (oType?.layout == ObjectType.Layout.SET) {
val layout = obj.layout
if (layout == ObjectType.Layout.SET) {
if (isDataViewEnabled.value) {
DashboardView.ObjectSet(
id = obj.id,
@ -436,7 +446,11 @@ class HomeDashboardViewModel(
title = obj.name,
isArchived = obj.isArchived ?: false,
isLoading = false,
emoji = obj.iconEmoji
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = urlBuilder
)
)
} else {
null
@ -453,7 +467,12 @@ class HomeDashboardViewModel(
type = obj.type.firstOrNull(),
typeName = oType?.name,
layout = obj.layout,
done = obj.done
done = obj.done,
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = urlBuilder
)
)
}
}
@ -470,8 +489,9 @@ class HomeDashboardViewModel(
inbox.value = objects
.map { ObjectWrapper.Basic(it) }
.mapNotNull { obj ->
val layout = obj.layout
val oType = stateData.value?.findOTypeById(obj.type)
if (oType?.layout == ObjectType.Layout.SET && !isDataViewEnabled.value) {
if (layout == ObjectType.Layout.SET && !isDataViewEnabled.value) {
null
} else {
DashboardView.Document(
@ -485,7 +505,12 @@ class HomeDashboardViewModel(
type = obj.type.firstOrNull(),
typeName = oType?.name,
layout = obj.layout,
done = obj.done
done = obj.done,
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = urlBuilder
)
)
}
}
@ -506,7 +531,11 @@ class HomeDashboardViewModel(
title = obj.name,
isArchived = obj.isArchived ?: false,
isLoading = false,
emoji = obj.iconEmoji
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = urlBuilder
)
)
}
},

View file

@ -10,6 +10,7 @@ import com.anytypeio.anytype.domain.config.GetDebugSettings
import com.anytypeio.anytype.domain.config.GetFlavourConfig
import com.anytypeio.anytype.domain.dashboard.interactor.*
import com.anytypeio.anytype.domain.event.interactor.InterceptEvents
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.page.CreatePage
class HomeDashboardViewModelFactory(
@ -27,7 +28,8 @@ class HomeDashboardViewModelFactory(
private val searchRecentObjects: SearchRecentObjects,
private val searchInboxObjects: SearchInboxObjects,
private val searchObjectSets: SearchObjectSets,
private val getFlavourConfig: GetFlavourConfig
private val getFlavourConfig: GetFlavourConfig,
private val urlBuilder: UrlBuilder
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
@ -47,7 +49,8 @@ class HomeDashboardViewModelFactory(
searchRecentObjects = searchRecentObjects,
searchInboxObjects = searchInboxObjects,
searchObjectSets = searchObjectSets,
getFlavourConfig = getFlavourConfig
getFlavourConfig = getFlavourConfig,
urlBuilder = urlBuilder
) as T
}
}

View file

@ -1,7 +1,9 @@
package com.anytypeio.anytype.presentation.extension
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.domain.`object`.ObjectWrapper
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.presentation.`object`.ObjectIcon
import com.anytypeio.anytype.presentation.desktop.DashboardView
fun List<DashboardView>.addAndSortByIds(
@ -44,6 +46,7 @@ fun List<DashboardView>.updateDetails(
}
is DashboardView.Document -> {
if (view.target == target) {
val obj = ObjectWrapper.Basic(details.map)
view.copy(
title = details.name,
emoji = details.iconEmoji?.let { name ->
@ -59,7 +62,12 @@ fun List<DashboardView>.updateDetails(
null
},
isArchived = details.isArchived ?: false,
isLoading = false
isLoading = false,
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = builder
)
)
} else {
view
@ -67,15 +75,15 @@ fun List<DashboardView>.updateDetails(
}
is DashboardView.ObjectSet -> {
if (view.target == target) {
val obj = ObjectWrapper.Basic(details.map)
view.copy(
title = details.name,
emoji = details.iconEmoji?.let { name ->
if (name.isNotEmpty())
name
else
null
},
isArchived = details.isArchived ?: false
isArchived = details.isArchived ?: false,
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = builder
)
)
} else {
view

View file

@ -1,9 +1,11 @@
package com.anytypeio.anytype.presentation.mapper
import com.anytypeio.anytype.core_models.*
import com.anytypeio.anytype.domain.`object`.ObjectWrapper
import com.anytypeio.anytype.domain.config.DebugSettings
import com.anytypeio.anytype.domain.misc.UrlBuilder
import com.anytypeio.anytype.domain.relations.Relations
import com.anytypeio.anytype.presentation.`object`.ObjectIcon
import com.anytypeio.anytype.presentation.desktop.DashboardView
import com.anytypeio.anytype.presentation.navigation.ObjectView
import com.anytypeio.anytype.presentation.page.editor.Markup
@ -320,7 +322,7 @@ fun List<Block>.toDashboardViews(
typeName = type?.name,
layout = layout
)
ObjectType.Layout.SET -> content.toSetView(block.id, details)
ObjectType.Layout.SET -> content.toSetView(block.id, details, builder)
else -> {
when (content.type) {
Block.Content.Link.Type.PAGE -> content.toPageView(
@ -331,7 +333,7 @@ fun List<Block>.toDashboardViews(
typeName = type?.name,
layout = layout
)
Block.Content.Link.Type.DATA_VIEW -> content.toSetView(block.id, details)
Block.Content.Link.Type.DATA_VIEW -> content.toSetView(block.id, details, builder)
Block.Content.Link.Type.ARCHIVE -> content.toArchiveView(block.id, details)
else -> null
}
@ -361,36 +363,48 @@ fun Block.Content.Link.toPageView(
typeName: String?,
type: String?
): DashboardView.Document {
val obj = ObjectWrapper.Basic(details.details[target]?.map ?: emptyMap())
return DashboardView.Document(
id = id,
target = target,
title = details.details[target]?.name,
emoji = details.details[target]?.iconEmoji?.let { name ->
if (name.isNotEmpty()) name else null
title = obj.name,
emoji = details.details[target]?.iconEmoji?.let { unicode ->
if (unicode.isNotEmpty()) unicode else null
},
image = details.details[target]?.iconImage?.let { name ->
if (name.isNotEmpty()) builder.image(name) else null
image = details.details[target]?.iconImage?.let { hash ->
if (hash.isNotEmpty()) builder.image(hash) else null
},
isArchived = details.details[target]?.isArchived ?: false,
isLoading = !details.details.containsKey(target),
typeName = typeName,
type = type,
layout = layout,
done = details.details[target]?.done
done = details.details[target]?.done,
icon = ObjectIcon.from(
obj = obj,
layout = layout,
builder = builder
)
)
}
fun Block.Content.Link.toSetView(
id: String,
details: Block.Details,
urlBuilder: UrlBuilder
): DashboardView.ObjectSet {
val obj = ObjectWrapper.Basic(details.details[target]?.map ?: emptyMap())
return DashboardView.ObjectSet(
id = id,
target = target,
title = details.details[target]?.name,
emoji = details.details[target]?.iconEmoji?.let { name ->
if (name.isNotEmpty()) name else null
},
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = urlBuilder
),
isArchived = details.details[target]?.isArchived ?: false
)
}

View file

@ -1,6 +1,9 @@
package com.anytypeio.anytype.presentation.`object`
import com.anytypeio.anytype.core_models.Hash
import com.anytypeio.anytype.core_models.ObjectType
import com.anytypeio.anytype.domain.`object`.ObjectWrapper
import com.anytypeio.anytype.domain.misc.UrlBuilder
sealed class ObjectIcon {
object None : ObjectIcon()
@ -9,9 +12,58 @@ sealed class ObjectIcon {
data class Image(val hash: Hash) : Basic()
data class Emoji(val unicode: String) : Basic()
}
sealed class Profile : ObjectIcon() {
data class Avatar(val name: String) : Profile()
data class Image(val hash: Hash) : Profile()
}
data class Task(val isChecked: Boolean) : ObjectIcon()
companion object {
fun from(
obj: ObjectWrapper.Basic,
layout: ObjectType.Layout?,
builder: UrlBuilder
): ObjectIcon = when (layout) {
ObjectType.Layout.BASIC -> {
val img = obj.iconImage
val emoji = obj.iconEmoji
when {
!img.isNullOrBlank() -> {
Basic.Image(hash = builder.thumbnail(img))
}
!emoji.isNullOrBlank() -> {
Basic.Emoji(unicode = emoji)
}
else -> {
Basic.Avatar(obj.name.orEmpty())
}
}
}
ObjectType.Layout.PROFILE -> {
val img = obj.iconImage
if (!img.isNullOrBlank()) {
Profile.Image(hash = builder.thumbnail(img))
} else {
Profile.Avatar(name = obj.name.orEmpty())
}
}
ObjectType.Layout.TODO -> {
Task(isChecked = obj.done ?: false)
}
ObjectType.Layout.SET -> {
val img = obj.iconImage
val emoji = obj.iconEmoji
if (!img.isNullOrBlank()) {
Basic.Image(hash = builder.thumbnail(img))
} else if (!emoji.isNullOrBlank()) {
Basic.Emoji(unicode = emoji)
} else {
None
}
}
else -> None
}
}
}

View file

@ -74,51 +74,16 @@ class ObjectSearchViewModel(
val targetType = listOfTypes.find { type ->
obj.type.contains(type.url)
}
var icon : ObjectIcon = ObjectIcon.None
when(targetType?.layout) {
ObjectType.Layout.BASIC -> {
val img = obj.iconImage
val emoji = obj.iconEmoji
icon = when {
!img.isNullOrBlank() -> {
ObjectIcon.Basic.Image(hash = urlBuilder.thumbnail(img))
}
!emoji.isNullOrBlank() -> {
ObjectIcon.Basic.Emoji(unicode = emoji)
}
else -> {
ObjectIcon.Basic.Avatar(obj.name.orEmpty())
}
}
}
ObjectType.Layout.PROFILE -> {
val img = obj.iconImage
icon = if (!img.isNullOrBlank()) {
ObjectIcon.Profile.Image(hash = urlBuilder.thumbnail(img))
} else {
ObjectIcon.Profile.Avatar(name = obj.name.orEmpty())
}
}
ObjectType.Layout.TODO -> {
icon = ObjectIcon.Task(isChecked = obj.done ?: false)
}
ObjectType.Layout.SET -> {
val img = obj.iconImage
val emoji = obj.iconEmoji
if (!img.isNullOrBlank()) {
icon = ObjectIcon.Basic.Image(hash = urlBuilder.thumbnail(img))
} else if (!emoji.isNullOrBlank()) {
icon = ObjectIcon.Basic.Emoji(unicode = emoji)
}
}
else -> {}
}
DefaultObjectView(
id = obj.id,
name = obj.name.orEmpty(),
typeName = targetType?.name.orEmpty(),
typeLayout = targetType?.layout,
icon = icon
typeLayout = obj.layout,
icon = ObjectIcon.from(
obj = obj,
layout = obj.layout,
builder = urlBuilder
)
)
}
}.collectLatest { views ->

View file

@ -105,7 +105,8 @@ open class DashboardTestSetup {
searchRecentObjects = searchRecentObjects,
searchInboxObjects = searchInboxObjects,
searchObjectSets = searchObjectSets,
getFlavourConfig = getFlavourConfig
getFlavourConfig = getFlavourConfig,
urlBuilder = builder
)
fun stubGetConfig(response: Either.Right<Config>) {

View file

@ -114,7 +114,8 @@ class HomeDashboardViewModelTest {
searchRecentObjects = searchRecentObjects,
searchInboxObjects = searchInboxObjects,
searchObjectSets = searchObjectSets,
getFlavourConfig = getFlavourConfig
getFlavourConfig = getFlavourConfig,
urlBuilder = builder
)
}