mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Page icon action menu (#536)
This commit is contained in:
parent
984f0b937c
commit
7a519e660a
32 changed files with 692 additions and 466 deletions
|
@ -5,10 +5,12 @@
|
|||
### New features 🚀
|
||||
|
||||
* Styling toolbar shows currently applied style in markup-styling mode (#525)
|
||||
* Wired document's icon with action menu (#529)
|
||||
|
||||
### Design & UX 🔳
|
||||
|
||||
*
|
||||
* Redesigned page emoji icon picker (#531)
|
||||
*
|
||||
|
||||
### Fixes & tech 🚒
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@ import com.agileburo.anytype.core_utils.di.scope.PerScreen
|
|||
import com.agileburo.anytype.domain.block.repo.BlockRepository
|
||||
import com.agileburo.anytype.domain.icon.SetIconName
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModelFactory
|
||||
import com.agileburo.anytype.ui.page.modals.PageIconPickerFragment
|
||||
import com.agileburo.anytype.ui.page.modals.DocumentEmojiIconPickerFragment
|
||||
import com.agileburo.anytype.ui.page.modals.actions.DocumentIconActionMenu
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.Subcomponent
|
||||
|
@ -19,7 +20,8 @@ interface PageIconPickerSubComponent {
|
|||
fun build(): PageIconPickerSubComponent
|
||||
}
|
||||
|
||||
fun inject(fragment: PageIconPickerFragment)
|
||||
fun inject(fragment: DocumentEmojiIconPickerFragment)
|
||||
fun inject(fragment: DocumentIconActionMenu)
|
||||
}
|
||||
|
||||
@Module
|
||||
|
|
|
@ -20,6 +20,8 @@ import androidx.lifecycle.Observer
|
|||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.ChangeBounds
|
||||
import androidx.transition.Fade
|
||||
import com.agileburo.anytype.R
|
||||
import com.agileburo.anytype.core_ui.common.Alignment
|
||||
import com.agileburo.anytype.core_ui.common.Markup
|
||||
|
@ -56,6 +58,7 @@ import com.agileburo.anytype.ui.base.NavigationFragment
|
|||
import com.agileburo.anytype.ui.menu.AnytypeContextMenu
|
||||
import com.agileburo.anytype.ui.page.modals.*
|
||||
import com.agileburo.anytype.ui.page.modals.actions.BlockActionToolbarFactory
|
||||
import com.agileburo.anytype.ui.page.modals.actions.DocumentIconActionMenu
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.hbisoft.pickit.PickiT
|
||||
import com.hbisoft.pickit.PickiTCallbacks
|
||||
|
@ -515,8 +518,27 @@ open class PageFragment :
|
|||
private fun execute(event: EventWrapper<Command>) {
|
||||
event.getContentIfNotHandled()?.let { command ->
|
||||
when (command) {
|
||||
is Command.OpenPagePicker -> {
|
||||
PageIconPickerFragment.newInstance(
|
||||
is Command.OpenDocumentIconActionMenu -> {
|
||||
hideSoftInput()
|
||||
if (recycler.scrollY > 0) recycler.smoothScrollToPosition(0)
|
||||
val shared = recycler.getChildAt(0).findViewById<TextView>(R.id.logo)
|
||||
val fr = DocumentIconActionMenu.new(
|
||||
y = shared.y + dimen(R.dimen.dp_48),
|
||||
emoji = shared.text.toString(),
|
||||
target = command.target
|
||||
).apply {
|
||||
enterTransition = Fade()
|
||||
exitTransition = Fade()
|
||||
sharedElementEnterTransition = ChangeBounds()
|
||||
}
|
||||
childFragmentManager.beginTransaction()
|
||||
.add(R.id.root, fr)
|
||||
.addToBackStack(null)
|
||||
.apply { addSharedElement(shared, getString(R.string.logo_transition)) }
|
||||
.commit()
|
||||
}
|
||||
is Command.OpenDocumentEmojiIconPicker -> {
|
||||
DocumentEmojiIconPickerFragment.newInstance(
|
||||
context = requireArguments().getString(ID_KEY, ID_EMPTY_VALUE),
|
||||
target = command.target
|
||||
).show(childFragmentManager, null)
|
||||
|
|
|
@ -15,18 +15,18 @@ import com.agileburo.anytype.R
|
|||
import com.agileburo.anytype.core_utils.ext.toast
|
||||
import com.agileburo.anytype.core_utils.ui.BaseBottomSheetFragment
|
||||
import com.agileburo.anytype.di.common.componentManager
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerAdapter
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModel
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModel.Contract
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModel.ViewState
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerAdapter
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerViewHolder
|
||||
import com.agileburo.anytype.presentation.page.picker.DocumentIconPickerViewModel
|
||||
import com.agileburo.anytype.presentation.page.picker.DocumentIconPickerViewModel.Contract
|
||||
import com.agileburo.anytype.presentation.page.picker.DocumentIconPickerViewModel.ViewState
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModelFactory
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import kotlinx.android.synthetic.main.fragment_page_icon_picker.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class PageIconPickerFragment : BaseBottomSheetFragment() {
|
||||
class DocumentEmojiIconPickerFragment : BaseBottomSheetFragment() {
|
||||
|
||||
private val target: String
|
||||
get() = requireArguments()
|
||||
|
@ -44,22 +44,13 @@ class PageIconPickerFragment : BaseBottomSheetFragment() {
|
|||
private val vm by lazy {
|
||||
ViewModelProviders
|
||||
.of(this, factory)
|
||||
.get(PageIconPickerViewModel::class.java)
|
||||
.get(DocumentIconPickerViewModel::class.java)
|
||||
}
|
||||
|
||||
private val pageIconPickerAdapter by lazy {
|
||||
PageIconPickerAdapter(
|
||||
DocumentEmojiIconPickerAdapter(
|
||||
views = emptyList(),
|
||||
onUploadPhotoClicked = { toast(NOT_IMPLEMENTED_MESSAGE) },
|
||||
onFilterQueryChanged = { vm.onEvent(Contract.Event.OnFilterQueryChanged(it)) },
|
||||
onSetRandomEmojiClicked = {
|
||||
vm.onEvent(
|
||||
Contract.Event.OnSetRandomEmojiClicked(
|
||||
target = target,
|
||||
context = context
|
||||
)
|
||||
)
|
||||
},
|
||||
onEmojiClicked = { unicode, alias ->
|
||||
vm.onEvent(
|
||||
Contract.Event.OnEmojiClicked(
|
||||
|
@ -100,12 +91,9 @@ class PageIconPickerFragment : BaseBottomSheetFragment() {
|
|||
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int) =
|
||||
when (val type = pageIconPickerAdapter.getItemViewType(position)) {
|
||||
PageIconPickerViewHolder.HOLDER_UPLOAD_PHOTO -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
|
||||
PageIconPickerViewHolder.HOLDER_CHOOSE_EMOJI -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
|
||||
PageIconPickerViewHolder.HOLDER_PICK_RANDOM_EMOJI -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
|
||||
PageIconPickerViewHolder.HOLDER_EMOJI_CATEGORY_HEADER -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
|
||||
PageIconPickerViewHolder.HOLDER_EMOJI_FILTER -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
|
||||
PageIconPickerViewHolder.HOLDER_EMOJI_ITEM -> 1
|
||||
DocumentEmojiIconPickerViewHolder.HOLDER_EMOJI_ITEM -> 1
|
||||
DocumentEmojiIconPickerViewHolder.HOLDER_EMOJI_CATEGORY_HEADER -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
|
||||
DocumentEmojiIconPickerViewHolder.HOLDER_EMOJI_FILTER -> PAGE_ICON_PICKER_DEFAULT_SPAN_COUNT
|
||||
else -> throw IllegalStateException("$UNEXPECTED_VIEW_TYPE_MESSAGE: $type")
|
||||
}
|
||||
}
|
||||
|
@ -114,15 +102,6 @@ class PageIconPickerFragment : BaseBottomSheetFragment() {
|
|||
setHasStableIds(true)
|
||||
}
|
||||
}
|
||||
|
||||
remove.setOnClickListener {
|
||||
vm.onEvent(
|
||||
Contract.Event.OnRemoveEmojiSelected(
|
||||
context = context,
|
||||
target = target
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
|
@ -171,7 +150,7 @@ class PageIconPickerFragment : BaseBottomSheetFragment() {
|
|||
fun newInstance(
|
||||
context: String,
|
||||
target: String
|
||||
) = PageIconPickerFragment().apply {
|
||||
) = DocumentEmojiIconPickerFragment().apply {
|
||||
arguments = bundleOf(ARG_CONTEXT_ID_KEY to context, ARG_TARGET_ID_KEY to target)
|
||||
}
|
||||
|
||||
|
@ -181,7 +160,6 @@ class PageIconPickerFragment : BaseBottomSheetFragment() {
|
|||
private const val ARG_TARGET_ID_KEY = "arg.picker.target.id"
|
||||
private const val MISSING_TARGET_ERROR = "Missing target id"
|
||||
private const val MISSING_CONTEXT_ERROR = "Missing context id"
|
||||
private const val NOT_IMPLEMENTED_MESSAGE = "Not implemented"
|
||||
private const val UNEXPECTED_VIEW_TYPE_MESSAGE = "Unexpected view type"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package com.agileburo.anytype.ui.page.modals.actions
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import com.agileburo.anytype.R
|
||||
import com.agileburo.anytype.core_utils.ext.toast
|
||||
import com.agileburo.anytype.core_utils.ui.BaseFragment
|
||||
import com.agileburo.anytype.di.common.componentManager
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_CHOOSE_EMOJI
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_CHOOSE_RANDOM_EMOJI
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_CHOOSE_UPLOAD_PHOTO
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_REMOVE
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.ActionMenuDivider
|
||||
import com.agileburo.anytype.presentation.page.picker.DocumentIconPickerViewModel
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModelFactory
|
||||
import com.agileburo.anytype.ui.page.modals.DocumentEmojiIconPickerFragment
|
||||
import kotlinx.android.synthetic.main.action_toolbar_page_icon.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class DocumentIconActionMenu : BaseFragment(R.layout.action_toolbar_page_icon),
|
||||
Observer<DocumentIconPickerViewModel.ViewState> {
|
||||
|
||||
private val target: String
|
||||
get() = requireArguments()
|
||||
.getString(ARG_TARGET_ID_KEY)
|
||||
?: throw IllegalStateException(MISSING_TARGET_ERROR)
|
||||
|
||||
@Inject
|
||||
lateinit var factory: PageIconPickerViewModelFactory
|
||||
|
||||
private val vm by lazy {
|
||||
ViewModelProviders
|
||||
.of(this, factory)
|
||||
.get(DocumentIconPickerViewModel::class.java)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
vm.state.observe(viewLifecycleOwner, this)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
container.setOnClickListener { exit() }
|
||||
|
||||
arguments?.getString(EMOJI_KEY)?.let { emoji -> logo.text = emoji }
|
||||
|
||||
setupLogoTranslation()
|
||||
setupAdapter()
|
||||
showMenuWithAnimation()
|
||||
}
|
||||
|
||||
private fun setupLogoTranslation() {
|
||||
val y = arguments?.getFloat(Y_KEY)
|
||||
if (y != null && y != 0.0f) {
|
||||
val delta = y - logo.y
|
||||
logo.y = y
|
||||
menu.y = menu.y + delta
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMenuWithAnimation() {
|
||||
val xAnim = menu.animate().scaleX(1f).apply {
|
||||
duration = ANIM_DURATION
|
||||
startDelay = ANIM_START_DELAY
|
||||
interpolator = OvershootInterpolator()
|
||||
}
|
||||
val yAnim = menu.animate().scaleY(1f).apply {
|
||||
duration = ANIM_DURATION
|
||||
startDelay = ANIM_START_DELAY
|
||||
interpolator = OvershootInterpolator()
|
||||
}
|
||||
|
||||
xAnim.start()
|
||||
yAnim.start()
|
||||
}
|
||||
|
||||
private fun setupAdapter() {
|
||||
|
||||
val drawable = requireContext().getDrawable(R.drawable.action_menu_divider)
|
||||
|
||||
checkNotNull(drawable)
|
||||
|
||||
val divider = ActionMenuDivider(drawable)
|
||||
|
||||
recycler.apply {
|
||||
addItemDecoration(divider)
|
||||
adapter = ActionMenuAdapter(
|
||||
options = intArrayOf(
|
||||
OPTION_CHOOSE_EMOJI,
|
||||
OPTION_CHOOSE_RANDOM_EMOJI,
|
||||
OPTION_CHOOSE_UPLOAD_PHOTO,
|
||||
OPTION_REMOVE
|
||||
)
|
||||
) { option ->
|
||||
when (option) {
|
||||
OPTION_CHOOSE_EMOJI -> {
|
||||
parentFragment?.childFragmentManager?.let { manager ->
|
||||
manager.popBackStack()
|
||||
DocumentEmojiIconPickerFragment.newInstance(
|
||||
context = target,
|
||||
target = target
|
||||
).show(manager, null)
|
||||
}
|
||||
}
|
||||
OPTION_REMOVE -> vm.onEvent(
|
||||
DocumentIconPickerViewModel.Contract.Event.OnRemoveEmojiSelected(
|
||||
context = target,
|
||||
target = target
|
||||
)
|
||||
)
|
||||
OPTION_CHOOSE_RANDOM_EMOJI -> vm.onEvent(
|
||||
DocumentIconPickerViewModel.Contract.Event.OnSetRandomEmojiClicked(
|
||||
context = target,
|
||||
target = target
|
||||
)
|
||||
)
|
||||
else -> toast("Not implemented")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChanged(state: DocumentIconPickerViewModel.ViewState) {
|
||||
when (state) {
|
||||
is DocumentIconPickerViewModel.ViewState.Exit -> exit()
|
||||
is DocumentIconPickerViewModel.ViewState.Error -> toast(state.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun exit() {
|
||||
parentFragment?.childFragmentManager?.popBackStack()
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().pageIconPickerSubComponent.get().inject(this)
|
||||
}
|
||||
|
||||
override fun releaseDependencies() {
|
||||
componentManager().pageIconPickerSubComponent.release()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun new(
|
||||
y: Float?,
|
||||
emoji: String?,
|
||||
target: String
|
||||
): DocumentIconActionMenu = DocumentIconActionMenu().apply {
|
||||
arguments = bundleOf(
|
||||
Y_KEY to y,
|
||||
EMOJI_KEY to emoji,
|
||||
ARG_TARGET_ID_KEY to target
|
||||
)
|
||||
}
|
||||
|
||||
private const val Y_KEY = "y"
|
||||
private const val EMOJI_KEY = "emoji"
|
||||
private const val ANIM_START_DELAY = 200L
|
||||
private const val ANIM_DURATION = 200L
|
||||
private const val ARG_TARGET_ID_KEY = "arg.picker.target.id"
|
||||
private const val MISSING_TARGET_ERROR = "Missing target id"
|
||||
}
|
||||
}
|
46
app/src/main/res/layout/action_toolbar_page_icon.xml
Normal file
46
app/src/main/res/layout/action_toolbar_page_icon.xml
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.motion.widget.MotionLayout 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:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#52000000">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:background="@drawable/rectangle_default_page_logo_background"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/emoji_color"
|
||||
android:textSize="28sp"
|
||||
android:transitionName="@string/logo_transition"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="🚀" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:scaleX="0.5"
|
||||
android:scaleY="0.5"
|
||||
android:id="@+id/menu"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginTop="16dp"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/logo"
|
||||
app:layout_constraintWidth_percent="0.7">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/action_toolbar_page_icon_item" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</androidx.constraintlayout.motion.widget.MotionLayout>
|
|
@ -21,26 +21,6 @@
|
|||
android:layout_marginTop="6dp"
|
||||
android:background="@drawable/page_icon_picker_dragger_background" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="30dp"
|
||||
android:fontFamily="@font/graphik_semibold"
|
||||
android:text="@string/page_icon"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="17sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="30dp"
|
||||
android:text="@string/page_icon_picker_remove_text"
|
||||
android:textColor="#ACA996"
|
||||
android:textSize="17sp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
|
|
|
@ -4,8 +4,7 @@ import android.content.Context
|
|||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import com.agileburo.anytype.core_ui.R
|
||||
|
||||
class ListDividerItemDecoration(context: Context) :
|
||||
DividerItemDecoration(context, VERTICAL) {
|
||||
class ListDividerItemDecoration(context: Context) : DividerItemDecoration(context, VERTICAL) {
|
||||
|
||||
init {
|
||||
context.getDrawable(R.drawable.divider)?.let {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
android:paddingEnd="20dp">
|
||||
|
||||
<TextView
|
||||
android:transitionName="@string/logo_transition"
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
<dimen name="dp_16">16dp</dimen>
|
||||
<dimen name="dp_12">12dp</dimen>
|
||||
<dimen name="dp_48">48dp</dimen>
|
||||
<dimen name="dp_45">45dp</dimen>
|
||||
<dimen name="dp_203">203dp</dimen>
|
||||
|
||||
<dimen name="roundedTextBorderRadius">4dp</dimen>
|
||||
|
|
|
@ -202,4 +202,7 @@
|
|||
<string name="redo">Redo</string>
|
||||
<string name="copy">Copy</string>
|
||||
|
||||
<string name="choose_emoji">Choose emoji</string>
|
||||
<string name="logo_transition">logo_transition</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.model
|
||||
|
||||
import com.agileburo.anytype.core_ui.common.ViewType
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerViewHolder.Companion.HOLDER_EMOJI_CATEGORY_HEADER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerViewHolder.Companion.HOLDER_EMOJI_FILTER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerViewHolder.Companion.HOLDER_EMOJI_ITEM
|
||||
|
||||
sealed class DocumentEmojiIconPickerView : ViewType {
|
||||
/**
|
||||
* @property alias short name or convenient name for an emoji.
|
||||
*/
|
||||
data class Emoji(
|
||||
val alias: String,
|
||||
val unicode: String
|
||||
) : DocumentEmojiIconPickerView() {
|
||||
override fun getViewType() = HOLDER_EMOJI_ITEM
|
||||
}
|
||||
|
||||
/**
|
||||
* @property category emoji category
|
||||
*/
|
||||
data class GroupHeader(
|
||||
val category: String
|
||||
) : DocumentEmojiIconPickerView() {
|
||||
override fun getViewType() = HOLDER_EMOJI_CATEGORY_HEADER
|
||||
}
|
||||
|
||||
/**
|
||||
* Emoji filter.
|
||||
*/
|
||||
object EmojiFilter : DocumentEmojiIconPickerView() {
|
||||
override fun getViewType() = HOLDER_EMOJI_FILTER
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.model
|
||||
|
||||
import com.agileburo.anytype.core_ui.common.ViewType
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_CHOOSE_EMOJI
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_CATEGORY_HEADER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_FILTER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_ITEM
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_PICK_RANDOM_EMOJI
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_UPLOAD_PHOTO
|
||||
|
||||
sealed class PageIconPickerView : ViewType {
|
||||
|
||||
/**
|
||||
* @property alias short name or convenient name for an emoji.
|
||||
*/
|
||||
data class Emoji(
|
||||
val alias: String,
|
||||
val unicode: String
|
||||
) : PageIconPickerView() {
|
||||
override fun getViewType() = HOLDER_EMOJI_ITEM
|
||||
}
|
||||
|
||||
/**
|
||||
* @property category emoji category
|
||||
*/
|
||||
data class GroupHeader(
|
||||
val category: String
|
||||
) : PageIconPickerView() {
|
||||
override fun getViewType() = HOLDER_EMOJI_CATEGORY_HEADER
|
||||
}
|
||||
|
||||
/**
|
||||
* Emoji filter.
|
||||
*/
|
||||
object EmojiFilter : PageIconPickerView() {
|
||||
override fun getViewType() = HOLDER_EMOJI_FILTER
|
||||
}
|
||||
|
||||
/**
|
||||
* User actions related to emoji picker feature.
|
||||
*/
|
||||
sealed class Action : PageIconPickerView() {
|
||||
object UploadPhoto : Action() {
|
||||
override fun getViewType() = HOLDER_UPLOAD_PHOTO
|
||||
}
|
||||
object PickRandomly : Action() {
|
||||
override fun getViewType() = HOLDER_PICK_RANDOM_EMOJI
|
||||
}
|
||||
object ChooseEmoji : Action() {
|
||||
override fun getViewType() = HOLDER_CHOOSE_EMOJI
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@ package com.agileburo.anytype.library_page_icon_picker_widget.model
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
|
||||
class PageIconPickerViewDiffUtil(
|
||||
private val old: List<PageIconPickerView>,
|
||||
private val new: List<PageIconPickerView>
|
||||
private val old: List<DocumentEmojiIconPickerView>,
|
||||
private val new: List<DocumentEmojiIconPickerView>
|
||||
) : DiffUtil.Callback() {
|
||||
|
||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.ui
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.R
|
||||
import kotlinx.android.synthetic.main.action_toolbar_page_icon_item.view.*
|
||||
|
||||
class ActionMenuAdapter(
|
||||
private val options : IntArray,
|
||||
private val onClick: (Int) -> Unit
|
||||
) : RecyclerView.Adapter<ActionMenuAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup, viewType: Int
|
||||
): ViewHolder = ViewHolder(
|
||||
view = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.action_toolbar_page_icon_item,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
override fun getItemCount(): Int = options.size
|
||||
|
||||
override fun onBindViewHolder(
|
||||
holder: ViewHolder, position: Int
|
||||
) = holder.bind(options[position], onClick)
|
||||
|
||||
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val title = itemView.title
|
||||
private val icon = itemView.icon
|
||||
|
||||
fun bind(
|
||||
option: Int,
|
||||
onClick: (Int) -> Unit
|
||||
) {
|
||||
itemView.setOnClickListener { onClick(option) }
|
||||
when(option) {
|
||||
OPTION_CHOOSE_EMOJI -> {
|
||||
title.setText(R.string.page_icon_picker_choose_emoji)
|
||||
icon.setImageResource(R.drawable.ic_page_icon_picker_choose_emoji)
|
||||
}
|
||||
OPTION_CHOOSE_RANDOM_EMOJI -> {
|
||||
title.setText(R.string.page_icon_picker_pick_emoji_randomly)
|
||||
icon.setImageResource(R.drawable.ic_page_icon_picker_random_emoji)
|
||||
}
|
||||
OPTION_CHOOSE_UPLOAD_PHOTO -> {
|
||||
title.setText(R.string.page_icon_picker_upload_photo)
|
||||
icon.setImageResource(R.drawable.ic_page_icon_picker_upload_photo)
|
||||
}
|
||||
OPTION_REMOVE -> {
|
||||
title.setText(R.string.page_icon_picker_remove_text)
|
||||
icon.setImageResource(R.drawable.ic_remove_page_icon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val OPTION_CHOOSE_EMOJI = 0
|
||||
const val OPTION_CHOOSE_RANDOM_EMOJI = 1
|
||||
const val OPTION_CHOOSE_UPLOAD_PHOTO = 2
|
||||
const val OPTION_REMOVE = 3
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.ui
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
class ActionMenuDivider(private val divider: Drawable) : RecyclerView.ItemDecoration() {
|
||||
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val dividerLeft = parent.paddingLeft
|
||||
val dividerRight = parent.width - parent.paddingRight
|
||||
val count = parent.childCount
|
||||
for (i in 0..count - 2) {
|
||||
val child = parent.getChildAt(i)
|
||||
val params = child.layoutParams as RecyclerView.LayoutParams
|
||||
val dividerTop = child.bottom + params.bottomMargin
|
||||
val dividerBottom = dividerTop + divider.intrinsicHeight
|
||||
divider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom)
|
||||
divider.draw(c)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.ui
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.R
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.DocumentEmojiIconPickerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerViewDiffUtil
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerViewHolder.Companion.HOLDER_EMOJI_CATEGORY_HEADER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerViewHolder.Companion.HOLDER_EMOJI_FILTER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.DocumentEmojiIconPickerViewHolder.Companion.HOLDER_EMOJI_ITEM
|
||||
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_filter.view.*
|
||||
|
||||
class DocumentEmojiIconPickerAdapter(
|
||||
private var views: List<DocumentEmojiIconPickerView>,
|
||||
private val onFilterQueryChanged: (String) -> Unit,
|
||||
private val onEmojiClicked: (String, String) -> Unit
|
||||
) : RecyclerView.Adapter<DocumentEmojiIconPickerViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(
|
||||
parent: ViewGroup,
|
||||
viewType: Int
|
||||
): DocumentEmojiIconPickerViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
||||
return when (viewType) {
|
||||
HOLDER_EMOJI_CATEGORY_HEADER -> DocumentEmojiIconPickerViewHolder.CategoryHeader(
|
||||
view = inflater.inflate(
|
||||
R.layout.item_page_icon_picker_emoji_category_header,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
HOLDER_EMOJI_ITEM -> DocumentEmojiIconPickerViewHolder.EmojiItem(
|
||||
view = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.item_page_icon_picker_emoji_item,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
HOLDER_EMOJI_FILTER -> DocumentEmojiIconPickerViewHolder.EmojiFilter(
|
||||
view = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.item_page_icon_picker_emoji_filter,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
).apply {
|
||||
itemView.filterInputField.doOnTextChanged { text, _, _, _ ->
|
||||
onFilterQueryChanged(text.toString())
|
||||
}
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected view type: $viewType")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = views.size
|
||||
override fun getItemViewType(position: Int) = views[position].getViewType()
|
||||
|
||||
override fun onBindViewHolder(holder: DocumentEmojiIconPickerViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is DocumentEmojiIconPickerViewHolder.CategoryHeader -> {
|
||||
holder.bind(views[position] as DocumentEmojiIconPickerView.GroupHeader)
|
||||
}
|
||||
is DocumentEmojiIconPickerViewHolder.EmojiItem -> {
|
||||
holder.bind(
|
||||
item = views[position] as DocumentEmojiIconPickerView.Emoji,
|
||||
onEmojiClicked = onEmojiClicked
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun update(update: List<DocumentEmojiIconPickerView>) {
|
||||
val result = DiffUtil.calculateDiff(
|
||||
PageIconPickerViewDiffUtil(
|
||||
old = views,
|
||||
new = update
|
||||
)
|
||||
)
|
||||
views = update
|
||||
result.dispatchUpdatesTo(this)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.ui
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.DocumentEmojiIconPickerView
|
||||
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_category_header.view.*
|
||||
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_item.view.*
|
||||
|
||||
sealed class DocumentEmojiIconPickerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
class CategoryHeader(view: View) : DocumentEmojiIconPickerViewHolder(view) {
|
||||
|
||||
private val category = itemView.category
|
||||
|
||||
fun bind(item: DocumentEmojiIconPickerView.GroupHeader) {
|
||||
category.text = item.category
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EmojiItem(view: View) : DocumentEmojiIconPickerViewHolder(view) {
|
||||
|
||||
private val emoji = itemView.emoji
|
||||
|
||||
fun bind(
|
||||
item: DocumentEmojiIconPickerView.Emoji,
|
||||
onEmojiClicked: (String, String) -> Unit
|
||||
) {
|
||||
emoji.text = item.unicode
|
||||
itemView.setOnClickListener { onEmojiClicked(item.unicode, item.alias) }
|
||||
}
|
||||
}
|
||||
|
||||
class EmojiFilter(view: View) : DocumentEmojiIconPickerViewHolder(view)
|
||||
|
||||
companion object {
|
||||
const val HOLDER_EMOJI_CATEGORY_HEADER = 1
|
||||
const val HOLDER_EMOJI_ITEM = 2
|
||||
const val HOLDER_EMOJI_FILTER = 3
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.ui
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.R
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerViewDiffUtil
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_CHOOSE_EMOJI
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_CATEGORY_HEADER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_FILTER
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_EMOJI_ITEM
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_PICK_RANDOM_EMOJI
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.ui.PageIconPickerViewHolder.Companion.HOLDER_UPLOAD_PHOTO
|
||||
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_filter.view.*
|
||||
|
||||
class PageIconPickerAdapter(
|
||||
private var views: List<PageIconPickerView>,
|
||||
private val onUploadPhotoClicked: () -> Unit,
|
||||
private val onSetRandomEmojiClicked: () -> Unit,
|
||||
private val onFilterQueryChanged: (String) -> Unit,
|
||||
private val onEmojiClicked: (String, String) -> Unit
|
||||
) : RecyclerView.Adapter<PageIconPickerViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageIconPickerViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
|
||||
return when (viewType) {
|
||||
HOLDER_UPLOAD_PHOTO -> PageIconPickerViewHolder.UploadPhoto(
|
||||
view = inflater.inflate(
|
||||
R.layout.item_page_icon_picker_upload_photo,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
).apply {
|
||||
itemView.setOnClickListener { onUploadPhotoClicked() }
|
||||
}
|
||||
HOLDER_PICK_RANDOM_EMOJI -> PageIconPickerViewHolder.PickRandom(
|
||||
view = inflater.inflate(
|
||||
R.layout.item_page_icon_picker_pick_emoji_randomly,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
).apply {
|
||||
itemView.setOnClickListener { onSetRandomEmojiClicked() }
|
||||
}
|
||||
HOLDER_CHOOSE_EMOJI -> PageIconPickerViewHolder.ChooseEmoji(
|
||||
view = inflater.inflate(
|
||||
R.layout.item_page_icon_picker_choose_emoji,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
HOLDER_EMOJI_CATEGORY_HEADER -> PageIconPickerViewHolder.CategoryHeader(
|
||||
view = inflater.inflate(
|
||||
R.layout.item_page_icon_picker_emoji_category_header,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
HOLDER_EMOJI_ITEM -> PageIconPickerViewHolder.EmojiItem(
|
||||
view = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.item_page_icon_picker_emoji_item,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
)
|
||||
HOLDER_EMOJI_FILTER -> PageIconPickerViewHolder.EmojiFilter(
|
||||
view = LayoutInflater.from(parent.context).inflate(
|
||||
R.layout.item_page_icon_picker_emoji_filter,
|
||||
parent,
|
||||
false
|
||||
)
|
||||
).apply {
|
||||
itemView.filterInputField.doOnTextChanged { text, _, _, _ ->
|
||||
onFilterQueryChanged(text.toString())
|
||||
}
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected view type: $viewType")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = views.size
|
||||
override fun getItemViewType(position: Int) = views[position].getViewType()
|
||||
|
||||
override fun onBindViewHolder(holder: PageIconPickerViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is PageIconPickerViewHolder.CategoryHeader -> {
|
||||
holder.bind(views[position] as PageIconPickerView.GroupHeader)
|
||||
}
|
||||
is PageIconPickerViewHolder.EmojiItem -> {
|
||||
holder.bind(
|
||||
item = views[position] as PageIconPickerView.Emoji,
|
||||
onEmojiClicked = onEmojiClicked
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun update(update: List<PageIconPickerView>) {
|
||||
val result = DiffUtil.calculateDiff(
|
||||
PageIconPickerViewDiffUtil(
|
||||
old = views,
|
||||
new = update
|
||||
)
|
||||
)
|
||||
views = update
|
||||
result.dispatchUpdatesTo(this)
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget.ui
|
||||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
|
||||
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_category_header.view.*
|
||||
import kotlinx.android.synthetic.main.item_page_icon_picker_emoji_item.view.*
|
||||
|
||||
sealed class PageIconPickerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
class UploadPhoto(view: View) : PageIconPickerViewHolder(view)
|
||||
|
||||
class PickRandom(view: View) : PageIconPickerViewHolder(view)
|
||||
|
||||
class ChooseEmoji(view: View) : PageIconPickerViewHolder(view)
|
||||
|
||||
class CategoryHeader(view: View) : PageIconPickerViewHolder(view) {
|
||||
|
||||
private val category = itemView.category
|
||||
|
||||
fun bind(item: PageIconPickerView.GroupHeader) {
|
||||
category.text = item.category
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class EmojiItem(view: View) : PageIconPickerViewHolder(view) {
|
||||
|
||||
private val emoji = itemView.emoji
|
||||
|
||||
fun bind(
|
||||
item: PageIconPickerView.Emoji,
|
||||
onEmojiClicked: (String, String) -> Unit
|
||||
) {
|
||||
emoji.text = item.unicode
|
||||
itemView.setOnClickListener { onEmojiClicked(item.unicode, item.alias) }
|
||||
}
|
||||
}
|
||||
|
||||
class EmojiFilter(view: View) : PageIconPickerViewHolder(view)
|
||||
|
||||
companion object {
|
||||
const val HOLDER_UPLOAD_PHOTO = 0
|
||||
const val HOLDER_PICK_RANDOM_EMOJI = 1
|
||||
const val HOLDER_CHOOSE_EMOJI = 2
|
||||
const val HOLDER_EMOJI_CATEGORY_HEADER = 3
|
||||
const val HOLDER_EMOJI_ITEM = 4
|
||||
const val HOLDER_EMOJI_FILTER = 5
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<size
|
||||
android:width="1dp"
|
||||
android:height="1dp" />
|
||||
<solid android:color="#EAE9E0" />
|
||||
</shape>
|
|
@ -4,17 +4,17 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M11.999,21C16.9696,21 20.999,16.9706 20.999,12C20.999,7.0294 16.9696,3 11.999,3C7.0285,3 2.999,7.0294 2.999,12C2.999,16.9706 7.0285,21 11.999,21ZM11.999,23C18.0742,23 22.999,18.0751 22.999,12C22.999,5.9249 18.0742,1 11.999,1C5.9239,1 0.999,5.9249 0.999,12C0.999,18.0751 5.9239,23 11.999,23Z" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M16.999,9.5C16.999,10.3284 16.3275,11 15.499,11C14.6706,11 13.999,10.3284 13.999,9.5C13.999,8.6716 14.6706,8 15.499,8C16.3275,8 16.999,8.6716 16.999,9.5Z" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M9.999,9.5C9.999,10.3284 9.3274,11 8.499,11C7.6706,11 6.999,10.3284 6.999,9.5C6.999,8.6716 7.6706,8 8.499,8C9.3274,8 9.999,8.6716 9.999,9.5Z" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M5.2889,14C6.1495,16.8915 8.828,19 11.9991,19C15.1701,19 17.8486,16.8915 18.7092,14H5.2889Z" />
|
||||
</vector>
|
||||
|
|
|
@ -7,20 +7,20 @@
|
|||
android:fillColor="#00000000"
|
||||
android:pathData="M4.998,3L18.9981,3A2,2 0,0 1,20.9981 5L20.9981,19A2,2 0,0 1,18.9981 21L4.998,21A2,2 0,0 1,2.998 19L2.998,5A2,2 0,0 1,4.998 3z"
|
||||
android:strokeWidth="2"
|
||||
android:strokeColor="#2C2B27" />
|
||||
android:strokeColor="#ACA996" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M7.9981,8m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M15.998,8m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M7.9981,16m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M15.998,16m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M11.998,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0" />
|
||||
</vector>
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M10.999,3C10.999,2.4477 11.4467,2 11.999,2C12.5513,2 12.999,2.4477 12.999,3V17C12.999,17.5523 12.5513,18 11.999,18C11.4467,18 10.999,17.5523 10.999,17V3Z" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:pathData="M4.999,22C4.4467,22 3.999,21.5523 3.999,21C3.999,20.4477 4.4467,20 4.999,20H18.999C19.5513,20 19.999,20.4477 19.999,21C19.999,21.5523 19.5513,22 18.999,22H4.999Z" />
|
||||
<path
|
||||
android:fillColor="#2C2B27"
|
||||
android:fillColor="#ACA996"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M11.999,1.5858L19.7061,9.2929C20.0967,9.6834 20.0967,10.3166 19.7061,10.7071C19.3156,11.0977 18.6824,11.0977 18.2919,10.7071L11.999,4.4142L5.7061,10.7071C5.3156,11.0977 4.6824,11.0977 4.2919,10.7071C3.9014,10.3166 3.9014,9.6834 4.2919,9.2929L11.999,1.5858Z" />
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M9.5,8H11V18H9.5V8Z"
|
||||
android:fillColor="#ACA996"/>
|
||||
<path
|
||||
android:pathData="M13,8H14.5V18H13V8Z"
|
||||
android:fillColor="#ACA996"/>
|
||||
<path
|
||||
android:pathData="M4.7431,6.5C4.3288,6.5 4,6.1642 4,5.75C4,5.3358 4.3358,5 4.75,5L19.25,5C19.6642,5 20,5.3358 20,5.75C20,6.1642 19.6705,6.5 19.2563,6.5C16.4869,6.5 7.4099,6.5 4.7431,6.5Z"
|
||||
android:fillColor="#ACA996"/>
|
||||
<path
|
||||
android:pathData="M14,3.5H10V5H14V3.5ZM10,2C9.1716,2 8.5,2.6716 8.5,3.5V6.5H15.5V3.5C15.5,2.6716 14.8284,2 14,2H10Z"
|
||||
android:fillColor="#ACA996"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:pathData="M5.2656,5L5.8686,18.1376C5.9421,19.7392 7.2621,21 8.8655,21H15.1372C16.7395,21 18.059,19.7409 18.1339,18.1403L18.75,4.9844L5.2656,5ZM6.836,6.4982L7.367,18.0688C7.4038,18.8696 8.0638,19.5 8.8655,19.5H15.1372C15.9383,19.5 16.5981,18.8704 16.6356,18.0702L17.178,6.4862L6.836,6.4982Z"
|
||||
android:fillColor="#ACA996"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:layout_width="match_parent" android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="16dp"
|
||||
android:textColor="@color/black"
|
||||
tools:text="Choose emoji"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:textSize="17sp"
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageView
|
||||
tools:background="@drawable/circle_solid_default"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:layout_gravity="end"
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,90 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget
|
||||
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.DocumentEmojiIconPickerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerViewDiffUtil
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DocumentEmojiIconPickerViewDiffUtilTest {
|
||||
|
||||
@Test
|
||||
fun `two emoji-filter items should be considered the same`() {
|
||||
val old = listOf(
|
||||
DocumentEmojiIconPickerView.EmojiFilter
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
DocumentEmojiIconPickerView.EmojiFilter
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = true,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two emoji items should be considered the same`() {
|
||||
val old = listOf(
|
||||
DocumentEmojiIconPickerView.Emoji(
|
||||
alias = "grining",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
DocumentEmojiIconPickerView.Emoji(
|
||||
alias = "grining",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = true,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two emoji items should be considered different`() {
|
||||
val old = listOf(
|
||||
DocumentEmojiIconPickerView.Emoji(
|
||||
alias = "smile",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
DocumentEmojiIconPickerView.Emoji(
|
||||
alias = "grining",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = false,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
package com.agileburo.anytype.library_page_icon_picker_widget
|
||||
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerViewDiffUtil
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class PageIconPickerViewDiffUtilTest {
|
||||
|
||||
@Test
|
||||
fun `two emoji-filter items should be considered the same`() {
|
||||
val old = listOf(
|
||||
PageIconPickerView.EmojiFilter
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
PageIconPickerView.EmojiFilter
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = true,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two upload-photo-action items should be considered the same`() {
|
||||
val old = listOf(
|
||||
PageIconPickerView.Action.UploadPhoto
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
PageIconPickerView.Action.UploadPhoto
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = true,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two choose-emoji-action items should be considered the same`() {
|
||||
val old = listOf(
|
||||
PageIconPickerView.Action.ChooseEmoji
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
PageIconPickerView.Action.ChooseEmoji
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = true,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two pick-random-emoji-action items should be considered the same`() {
|
||||
val old = listOf(
|
||||
PageIconPickerView.Action.PickRandomly
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
PageIconPickerView.Action.PickRandomly
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = true,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two emoji items should be considered the same`() {
|
||||
val old = listOf(
|
||||
PageIconPickerView.Emoji(
|
||||
alias = "grining",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
PageIconPickerView.Emoji(
|
||||
alias = "grining",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = true,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `two emoji items should be considered different`() {
|
||||
val old = listOf(
|
||||
PageIconPickerView.Emoji(
|
||||
alias = "smile",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val new = listOf(
|
||||
PageIconPickerView.Emoji(
|
||||
alias = "grining",
|
||||
unicode = "U+13131"
|
||||
)
|
||||
)
|
||||
|
||||
val util = PageIconPickerViewDiffUtil(
|
||||
old = old,
|
||||
new = new
|
||||
)
|
||||
|
||||
val result = util.areItemsTheSame(0, 0)
|
||||
|
||||
assertEquals(
|
||||
expected = false,
|
||||
actual = result
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1627,7 +1627,7 @@ class PageViewModel(
|
|||
}
|
||||
|
||||
fun onPageIconClicked() {
|
||||
dispatch(Command.OpenPagePicker(context))
|
||||
dispatch(Command.OpenDocumentIconActionMenu(context))
|
||||
}
|
||||
|
||||
private fun onFileClicked(id: String) {
|
||||
|
|
|
@ -5,7 +5,12 @@ import com.agileburo.anytype.domain.common.Id
|
|||
import com.agileburo.anytype.domain.common.Url
|
||||
|
||||
sealed class Command {
|
||||
data class OpenPagePicker(
|
||||
|
||||
data class OpenDocumentIconActionMenu(
|
||||
val target: String
|
||||
) : Command()
|
||||
|
||||
data class OpenDocumentEmojiIconPicker(
|
||||
val target: String
|
||||
) : Command()
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@ import androidx.lifecycle.viewModelScope
|
|||
import com.agileburo.anytype.core_utils.ui.ViewStateViewModel
|
||||
import com.agileburo.anytype.domain.base.Either
|
||||
import com.agileburo.anytype.domain.icon.SetIconName
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.PageIconPickerView
|
||||
import com.agileburo.anytype.library_page_icon_picker_widget.model.DocumentEmojiIconPickerView
|
||||
import com.agileburo.anytype.presentation.common.StateReducer
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModel.Contract.Event
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModel.Contract.State
|
||||
import com.agileburo.anytype.presentation.page.picker.PageIconPickerViewModel.ViewState
|
||||
import com.agileburo.anytype.presentation.page.picker.DocumentIconPickerViewModel.Contract.Event
|
||||
import com.agileburo.anytype.presentation.page.picker.DocumentIconPickerViewModel.Contract.State
|
||||
import com.agileburo.anytype.presentation.page.picker.DocumentIconPickerViewModel.ViewState
|
||||
import com.vdurmont.emoji.Emoji
|
||||
import com.vdurmont.emoji.EmojiManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -17,7 +17,7 @@ import kotlinx.coroutines.channels.ConflatedBroadcastChannel
|
|||
import kotlinx.coroutines.flow.*
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class PageIconPickerViewModel(
|
||||
class DocumentIconPickerViewModel(
|
||||
private val setIconName: SetIconName
|
||||
) : ViewStateViewModel<ViewState>(), StateReducer<State, Event> {
|
||||
|
||||
|
@ -30,10 +30,7 @@ class PageIconPickerViewModel(
|
|||
|
||||
|
||||
private val headers = listOf(
|
||||
PageIconPickerView.Action.UploadPhoto,
|
||||
PageIconPickerView.Action.PickRandomly,
|
||||
PageIconPickerView.Action.ChooseEmoji,
|
||||
PageIconPickerView.EmojiFilter
|
||||
DocumentEmojiIconPickerView.EmojiFilter
|
||||
)
|
||||
|
||||
init {
|
||||
|
@ -51,7 +48,6 @@ class PageIconPickerViewModel(
|
|||
.map { state ->
|
||||
when {
|
||||
state.error != null -> ViewState.Error(state.error)
|
||||
state.isLoading -> ViewState.Loading
|
||||
state.isCompleted -> ViewState.Exit
|
||||
else -> ViewState.Success(
|
||||
views = headers + map(state.selection)
|
||||
|
@ -142,12 +138,12 @@ class PageIconPickerViewModel(
|
|||
}
|
||||
|
||||
private suspend fun pickRandomEmoji(emojis: List<Emoji>): Emoji = withContext(Dispatchers.IO) {
|
||||
emojis.random()
|
||||
EmojiManager.getAll().random()
|
||||
}
|
||||
|
||||
private suspend fun map(emojis: List<Emoji>) = withContext(Dispatchers.IO) {
|
||||
emojis.map { emoji ->
|
||||
PageIconPickerView.Emoji(
|
||||
DocumentEmojiIconPickerView.Emoji(
|
||||
alias = emoji.aliases.first(),
|
||||
/**
|
||||
* Fix pirate flag emoji render, after fixing
|
||||
|
@ -176,7 +172,7 @@ class PageIconPickerViewModel(
|
|||
sealed class ViewState {
|
||||
object Loading : ViewState()
|
||||
object Exit : ViewState()
|
||||
data class Success(val views: List<PageIconPickerView>) : ViewState()
|
||||
data class Success(val views: List<DocumentEmojiIconPickerView>) : ViewState()
|
||||
data class Error(val message: String) : ViewState()
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ class PageIconPickerViewModelFactory(
|
|||
) : ViewModelProvider.Factory {
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T = PageIconPickerViewModel(
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T = DocumentIconPickerViewModel(
|
||||
setIconName = setIconName
|
||||
) as T
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue