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

DROID-1186 Editor | Design | Object appearance, cover (#31)

This commit is contained in:
Konstantin Ivanov 2023-06-07 12:41:48 +02:00 committed by GitHub
parent e6a0e3f9b9
commit 940b930a61
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 123 additions and 173 deletions

View file

@ -25,7 +25,6 @@ import com.anytypeio.anytype.di.feature.MainEntryModule
import com.anytypeio.anytype.di.feature.ManageViewerModule
import com.anytypeio.anytype.di.feature.ModifyViewerSortModule
import com.anytypeio.anytype.di.feature.MoveToModule
import com.anytypeio.anytype.di.feature.ObjectAppearanceCoverModule
import com.anytypeio.anytype.di.feature.ObjectAppearanceIconModule
import com.anytypeio.anytype.di.feature.ObjectAppearancePreviewLayoutModule
import com.anytypeio.anytype.di.feature.ObjectAppearanceSettingModule
@ -298,14 +297,6 @@ class ComponentManager(
.build()
}
val objectAppearanceCoverComponent = DependentComponentMap { ctx ->
editorComponent
.get(ctx)
.objectAppearanceCoverComponent()
.module(ObjectAppearanceCoverModule)
.build()
}
val objectAppearanceChooseDescriptionComponent = DependentComponentMap { ctx ->
editorComponent
.get(ctx)

View file

@ -177,7 +177,6 @@ interface EditorSubComponent {
fun objectAppearanceSettingComponent(): ObjectAppearanceSettingSubComponent.Builder
fun objectAppearanceIconComponent(): ObjectAppearanceIconSubComponent.Builder
fun objectAppearancePreviewLayoutComponent(): ObjectAppearancePreviewLayoutSubComponent.Builder
fun objectAppearanceCoverComponent(): ObjectAppearanceCoverSubComponent.Builder
fun objectAppearanceChooseDescription(): ObjectAppearanceChooseDescriptionSubComponent.Builder
fun setBlockTextValueComponent(): SetBlockTextValueSubComponent.Builder

View file

@ -5,13 +5,11 @@ import com.anytypeio.anytype.core_utils.di.scope.PerModal
import com.anytypeio.anytype.domain.block.interactor.SetLinkAppearance
import com.anytypeio.anytype.presentation.editor.Editor
import com.anytypeio.anytype.presentation.objects.appearance.ObjectAppearanceSettingViewModel
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChooseCoverViewModel
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChooseDescriptionViewModel
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChooseIconViewModel
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChoosePreviewLayoutViewModel
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.ui.objects.appearance.ObjectAppearanceSettingFragment
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChooseCoverFragment
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChooseDescriptionFragment
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChooseIconFragment
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChoosePreviewLayoutFragment
@ -120,40 +118,6 @@ object ObjectAppearancePreviewLayoutModule {
}
//endregion
//region COVER
@Subcomponent(modules = [ObjectAppearanceCoverModule::class])
@PerModal
interface ObjectAppearanceCoverSubComponent {
@Subcomponent.Builder
interface Builder {
fun module(module: ObjectAppearanceCoverModule): Builder
fun build(): ObjectAppearanceCoverSubComponent
}
fun inject(fragment: ObjectAppearanceChooseCoverFragment)
}
@Module
object ObjectAppearanceCoverModule {
@JvmStatic
@Provides
@PerModal
fun provideObjectAppearanceCoverViewModelFactory(
storage: Editor.Storage,
setLinkAppearance: SetLinkAppearance,
dispatcher: Dispatcher<Payload>
): ObjectAppearanceChooseCoverViewModel.Factory {
return ObjectAppearanceChooseCoverViewModel.Factory(
storage = storage,
setLinkAppearance = setLinkAppearance,
dispatcher = dispatcher
)
}
}
//endregion
@Subcomponent(modules = [ObjectAppearanceChooseDescriptionModule::class])
@PerModal
interface ObjectAppearanceChooseDescriptionSubComponent {

View file

@ -20,7 +20,6 @@ import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
import com.anytypeio.anytype.databinding.FragmentObjectAppearanceSettingBinding
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.objects.appearance.ObjectAppearanceSettingViewModel
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChooseCoverFragment
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChooseDescriptionFragment
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChooseIconFragment
import com.anytypeio.anytype.ui.objects.appearance.choose.ObjectAppearanceChoosePreviewLayoutFragment
@ -45,6 +44,13 @@ class ObjectAppearanceSettingFragment :
ctx = ctx,
isChecked = isChecked
)
},
onCoverToggleChanged = { isChecked ->
vm.updateCoverAppearance(
blockId = block,
ctx = ctx,
isCoverVisible = isChecked
)
}
)
}
@ -83,9 +89,6 @@ class ObjectAppearanceSettingFragment :
private fun observeCommands(command: ObjectAppearanceSettingViewModel.Command) {
val fr = when (command) {
ObjectAppearanceSettingViewModel.Command.CoverScreen -> {
ObjectAppearanceChooseCoverFragment.new(block = block, ctx = ctx)
}
ObjectAppearanceSettingViewModel.Command.IconScreen -> {
ObjectAppearanceChooseIconFragment.new(block = block, ctx = ctx)
}

View file

@ -1,35 +0,0 @@
package com.anytypeio.anytype.ui.objects.appearance.choose
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChooseCoverViewModel
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChooseSettingsView
import javax.inject.Inject
class ObjectAppearanceChooseCoverFragment :
ObjectAppearanceChooseFragmentBase<ObjectAppearanceChooseSettingsView.Cover, ObjectAppearanceChooseCoverViewModel>() {
@Inject
lateinit var factory: ObjectAppearanceChooseCoverViewModel.Factory
override val vm: ObjectAppearanceChooseCoverViewModel by viewModels { factory }
override val title: Int = R.string.cover
override fun injectDependencies() {
componentManager().objectAppearanceCoverComponent.get(ctx).inject(this)
}
override fun releaseDependencies() {
componentManager().objectAppearanceCoverComponent.release(ctx)
}
companion object {
fun new(ctx: Id, block: Id) = ObjectAppearanceChooseCoverFragment().apply {
arguments = bundleOf(CONTEXT_ID_KEY to ctx, BLOCK_ID_KEY to block)
}
}
}

View file

@ -6,11 +6,13 @@ import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.databinding.ItemObjectPreviewCoverBinding
import com.anytypeio.anytype.core_ui.databinding.ItemObjectPreviewRelationNameBinding
import com.anytypeio.anytype.core_ui.databinding.ItemObjectPreviewRelationToggleBinding
import com.anytypeio.anytype.core_ui.databinding.ItemObjectPreviewSectionBinding
import com.anytypeio.anytype.core_ui.databinding.ItemObjectPreviewSettingBinding
import com.anytypeio.anytype.core_ui.extensions.drawable
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView.Appearance.MenuItem
import com.anytypeio.anytype.presentation.objects.appearance.ObjectAppearanceMainSettingsView
import com.anytypeio.anytype.presentation.objects.appearance.ObjectAppearanceMainSettingsView.Cover
@ -23,7 +25,8 @@ import com.anytypeio.anytype.presentation.objects.appearance.ObjectAppearanceMai
class ObjectAppearanceSettingAdapter(
private val onItemClick: (ObjectAppearanceMainSettingsView) -> Unit,
private val onSettingToggleChanged: (Toggle, Boolean) -> Unit
private val onSettingToggleChanged: (Toggle, Boolean) -> Unit,
private val onCoverToggleChanged: (Boolean) -> Unit
) : RecyclerView.Adapter<ObjectAppearanceSettingAdapter.ViewHolder>() {
private val items: MutableList<ObjectAppearanceMainSettingsView> = mutableListOf()
@ -73,6 +76,19 @@ class ObjectAppearanceSettingAdapter(
}
}
}
TYPE_ITEM_COVER ->
ViewHolder.Cover(
binding = ItemObjectPreviewCoverBinding.inflate(
inflater, parent, false
)
).apply {
binding.coverSwitch.setOnCheckedChangeListener { _, isChecked ->
val pos = bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
onCoverToggleChanged(isChecked)
}
}
}
else -> throw IllegalStateException("Unexpected view type: $viewType")
}
}
@ -87,6 +103,7 @@ class ObjectAppearanceSettingAdapter(
is ViewHolder.Section -> {}
is ViewHolder.Relation.Toggle -> holder.bind(getItem(position) as Toggle)
is ViewHolder.List -> holder.bind(getItem(position) as ObjectAppearanceMainSettingsView.List)
is ViewHolder.Cover -> holder.bind(getItem(position) as Cover)
}
}
@ -94,8 +111,8 @@ class ObjectAppearanceSettingAdapter(
FeaturedRelationsSection -> TYPE_ITEM_SECTION
is Description,
is Icon,
is PreviewLayout,
is Cover -> TYPE_ITEM_SETTING_LIST
is PreviewLayout -> TYPE_ITEM_SETTING_LIST
is Cover -> TYPE_ITEM_COVER
is Relation.Name -> TYPE_ITEM_RELATION_NAME
is Relation.ObjectType -> TYPE_ITEM_RELATION_TOGGLE
}
@ -123,13 +140,7 @@ class ObjectAppearanceSettingAdapter(
MenuItem.Description.ADDED -> R.string.object_description
MenuItem.Description.CONTENT -> R.string.description_content
MenuItem.Description.NONE -> R.string.description_none
}
is Cover -> {
when (item.coverState) {
MenuItem.Cover.WITH -> R.string.visible
MenuItem.Cover.WITHOUT -> R.string.none
}
}
}.also { binding.relIcon.visible() }
is Icon -> {
when (item.icon) {
MenuItem.Icon.NONE -> R.string.none
@ -150,7 +161,6 @@ class ObjectAppearanceSettingAdapter(
@StringRes
private fun getName(item: ObjectAppearanceMainSettingsView.List): Int {
return when (item) {
is Cover -> R.string.cover
is Description -> R.string.description
is Icon -> R.string.icon
is PreviewLayout -> R.string.preview_layout
@ -188,6 +198,18 @@ class ObjectAppearanceSettingAdapter(
}
}
class Cover(
val binding: ItemObjectPreviewCoverBinding
) : ViewHolder(binding.root) {
fun bind(item: ObjectAppearanceMainSettingsView.Cover) {
when (item.coverState) {
MenuItem.Cover.WITH -> binding.coverSwitch.isChecked = true
MenuItem.Cover.WITHOUT -> binding.coverSwitch.isChecked = false
}
}
}
}
companion object {
@ -195,5 +217,6 @@ class ObjectAppearanceSettingAdapter(
private const val TYPE_ITEM_SETTING_LIST = 2
private const val TYPE_ITEM_RELATION_NAME = 5
private const val TYPE_ITEM_RELATION_TOGGLE = 6
private const val TYPE_ITEM_COVER = 7
}
}

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="52dp"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal">
<TextView
android:id="@+id/coverName"
style="@style/TextView.UXStyle.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="12dp"
android:layout_weight="1.0"
android:ellipsize="end"
android:text="@string/cover"
android:maxLines="1"
android:singleLine="true" />
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/coverSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="0dp"
app:useMaterialThemeColors="false"
app:splitTrack="false"
app:thumbTint="@drawable/viewer_relation_switch_thumb"
app:trackTint="@drawable/viewer_relation_switch_track"/>
</LinearLayout>

View file

@ -11,7 +11,7 @@
android:layout_height="wrap_content"
android:paddingTop="26dp"
android:paddingBottom="8dp"
android:text="@string/attributes"
android:text="@string/relations"
android:textColor="@color/text_secondary"
android:gravity="start|center_vertical"
tools:text="Relations"/>

View file

@ -1,8 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="52dp">
<com.anytypeio.anytype.core_ui.widgets.RelationFormatIconWidget
android:id="@+id/relIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:src="@drawable/ic_relation_desc_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/>
<TextView
android:id="@+id/settingName"
@ -10,8 +22,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="14dp"
android:layout_marginBottom="14dp"
android:layout_marginStart="10dp"
app:layout_goneMarginStart="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/relIcon"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.451"
tools:text="Card size" />
<TextView
@ -20,8 +36,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="18dp"
android:layout_marginEnd="11dp"
android:textColor="@color/text_secondary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/settingArrow"
app:layout_constraintTop_toTopOf="parent"
tools:text="Large" />
<ImageView
@ -29,6 +48,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:src="@drawable/ic_arrow_forward" />
android:src="@drawable/ic_arrow_forward"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -12,7 +12,7 @@ sealed interface ObjectAppearanceMainSettingsView {
sealed interface List : ObjectAppearanceMainSettingsView
data class PreviewLayout(val previewLayoutState: MenuItem.PreviewLayout) : List
data class Icon(val icon: MenuItem.Icon) : List
data class Cover(val coverState: MenuItem.Cover) : List
data class Cover(val coverState: MenuItem.Cover): ObjectAppearanceMainSettingsView
object FeaturedRelationsSection : ObjectAppearanceMainSettingsView

View file

@ -83,7 +83,6 @@ class ObjectAppearanceSettingViewModel(
fun onItemClicked(item: ObjectAppearanceMainSettingsView) {
viewModelScope.launch {
when (item) {
is Cover -> commands.emit(Command.CoverScreen)
is Icon -> commands.emit(Command.IconScreen)
is PreviewLayout -> commands.emit(Command.PreviewLayoutScreen)
is Relation.Description -> commands.emit(Command.DescriptionScreen)
@ -116,6 +115,25 @@ class ObjectAppearanceSettingViewModel(
}
}
fun updateCoverAppearance(ctx: Id, blockId: Id, isCoverVisible: Boolean) {
val block = storage.document.get().find { it.id == blockId }
if (block != null && block.content is Link) {
val content = block.content as Link
val newContent = updateAppearance(isCoverVisible, content)
setLinkAppearance(ctx, blockId, newContent)
}
}
private fun updateAppearance(isCoverVisible: Boolean, oldContent: Link): Link {
val relations = oldContent.relations
val updatedRelations = if (isCoverVisible) {
relations + Relations.COVER
} else {
relations - Relations.COVER
}
return oldContent.copy(relations = updatedRelations)
}
private fun setLinkAppearance(ctx: Id, blockId: Id, content: Link) {
viewModelScope.launch {
setLinkAppearance(
@ -138,7 +156,6 @@ class ObjectAppearanceSettingViewModel(
sealed class Command {
object IconScreen : Command()
object CoverScreen : Command()
object PreviewLayoutScreen : Command()
object DescriptionScreen : Command()
}

View file

@ -1,66 +0,0 @@
package com.anytypeio.anytype.presentation.objects.appearance.choose
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.core_models.Block
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_models.Relations
import com.anytypeio.anytype.domain.block.interactor.SetLinkAppearance
import com.anytypeio.anytype.presentation.editor.Editor
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.objects.appearance.choose.ObjectAppearanceChooseSettingsView.Cover
import com.anytypeio.anytype.presentation.util.Dispatcher
class ObjectAppearanceChooseCoverViewModel(
storage: Editor.Storage,
setLinkAppearance: SetLinkAppearance,
dispatcher: Dispatcher<Payload>
) : ObjectAppearanceChooseViewModelBase<Cover>(
storage, setLinkAppearance, dispatcher
) {
override fun getItems(menu: BlockView.Appearance.Menu): List<Cover> {
val coverState = menu.cover
return listOf(
Cover.None(
isSelected = coverState == BlockView.Appearance.MenuItem.Cover.WITHOUT
),
Cover.Visible(
isSelected = coverState == BlockView.Appearance.MenuItem.Cover.WITH
)
)
}
override fun updateAppearance(
item: Cover,
oldContent: Block.Content.Link
): Block.Content.Link {
val relations = oldContent.relations
return when (item) {
is Cover.None -> {
oldContent.copy(
relations = relations - Relations.COVER
)
}
is Cover.Visible -> {
oldContent.copy(
relations = relations + Relations.COVER
)
}
}
}
class Factory(
private val storage: Editor.Storage,
private val setLinkAppearance: SetLinkAppearance,
private val dispatcher: Dispatcher<Payload>
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return ObjectAppearanceChooseCoverViewModel(
storage,
setLinkAppearance,
dispatcher
) as T
}
}
}