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

Tech | Legacy (#2005)

* legacy

* legacy

* remove tests

* ci

* Update check.yml

Co-authored-by: konstantiniiv <ki@anytype.io>
This commit is contained in:
Konstantin Ivanov 2021-12-20 17:38:50 +02:00 committed by GitHub
parent 1ea7ad50e5
commit 3a256df698
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 2 additions and 7180 deletions

View file

@ -1,7 +1,7 @@
on:
pull_request:
# add "synchronize" in "types", in order to trigger workflow for pull request commit(s) pushes.
types: [opened, synchronize]
types: [opened]
branches: [develop]
name: Run debug unit tests
jobs:

View file

@ -165,7 +165,6 @@ dependencies {
implementation analyticsDependencies.amplitude
implementation analyticsDependencies.okhttp
implementation applicationDependencies.blurry
implementation applicationDependencies.shimmerLayout
implementation applicationDependencies.photoView
implementation applicationDependencies.zxing

View file

@ -135,14 +135,6 @@ class ComponentManager(private val main: MainComponent) {
.build()
}
val documentIconActionMenuComponent = DependentComponentMap { ctx ->
editorComponent
.get(ctx)
.documentActionMenuComponentBuilder()
.documentIconActionMenuModule(DocumentIconActionMenuModule())
.build()
}
val objectIconPickerComponent = DependentComponentMap { ctx ->
editorComponent
.get(ctx)

View file

@ -1,63 +0,0 @@
package com.anytypeio.anytype.di.feature
import com.anytypeio.anytype.core_models.Payload
import com.anytypeio.anytype.core_utils.di.scope.PerModal
import com.anytypeio.anytype.domain.block.repo.BlockRepository
import com.anytypeio.anytype.domain.icon.SetDocumentEmojiIcon
import com.anytypeio.anytype.domain.icon.SetDocumentImageIcon
import com.anytypeio.anytype.presentation.editor.editor.DetailModificationManager
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModelFactory
import com.anytypeio.anytype.presentation.util.Dispatcher
import com.anytypeio.anytype.ui.editor.modals.actions.DocumentIconActionMenuFragment
import com.anytypeio.anytype.ui.editor.modals.actions.ProfileIconActionMenuFragment
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
@Subcomponent(modules = [DocumentIconActionMenuModule::class])
@PerModal
interface DocumentActionMenuSubComponent {
@Subcomponent.Builder
interface Builder {
fun documentIconActionMenuModule(module: DocumentIconActionMenuModule): Builder
fun build(): DocumentActionMenuSubComponent
}
fun inject(fragment: DocumentIconActionMenuFragment)
fun inject(fragment: ProfileIconActionMenuFragment)
}
@Module
class DocumentIconActionMenuModule {
@Provides
@PerModal
fun provideDocumentIconActionMenuViewModelFactory(
setEmojiIcon: SetDocumentEmojiIcon,
setImageIcon: SetDocumentImageIcon,
dispatcher: Dispatcher<Payload>,
details: DetailModificationManager
): DocumentIconActionMenuViewModelFactory = DocumentIconActionMenuViewModelFactory(
setEmojiIcon = setEmojiIcon,
setImageIcon = setImageIcon,
dispatcher = dispatcher,
details = details
)
@Provides
@PerModal
fun provideSetDocumentEmojiIconUseCase(
repo: BlockRepository
): SetDocumentEmojiIcon = SetDocumentEmojiIcon(
repo = repo
)
@Provides
@PerModal
fun provideSetDocumentImageIconUseCase(
repo: BlockRepository
): SetDocumentImageIcon = SetDocumentImageIcon(
repo = repo
)
}

View file

@ -74,7 +74,6 @@ interface EditorSubComponent {
fun inject(fragment: EditorFragment)
fun objectIconPickerComponent(): ObjectIconPickerComponent.Builder
fun documentActionMenuComponentBuilder(): DocumentActionMenuSubComponent.Builder
// Relations

View file

@ -93,7 +93,6 @@ import com.anytypeio.anytype.ui.editor.cover.SelectCoverObjectFragment
import com.anytypeio.anytype.ui.editor.gallery.FullScreenPictureFragment
import com.anytypeio.anytype.ui.editor.layout.ObjectLayoutFragment
import com.anytypeio.anytype.ui.editor.modals.*
import com.anytypeio.anytype.ui.editor.modals.actions.BlockActionToolbarFactory
import com.anytypeio.anytype.ui.editor.sheets.ObjectMenuBaseFragment.DocumentMenuActionReceiver
import com.anytypeio.anytype.ui.editor.sheets.ObjectMenuFragment
import com.anytypeio.anytype.ui.linking.LinkToObjectFragment
@ -112,7 +111,6 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.Snackbar
import com.hbisoft.pickit.PickiT
import com.hbisoft.pickit.PickiTCallbacks
import jp.wasabeef.blurry.Blurry
import kotlinx.android.synthetic.main.fragment_editor.*
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
@ -787,11 +785,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
super.onDestroy()
}
override fun onBlockActionClicked(id: String, action: ActionItemType) {
Blurry.delete(root)
vm.onActionMenuItemClicked(id, action)
}
override fun onSetRelationKeyClicked(blockId: Id, key: Id) {
vm.onSetRelationKeyClicked(blockId = blockId, key = key)
}
@ -867,19 +860,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
is Command.PopBackStack -> {
childFragmentManager.popBackStack()
}
is Command.OpenActionBar -> {
lifecycleScope.launch {
if (root.isKeyboardVisible()) {
hideKeyboard()
delay(300)
blurContainer()
navigateToBlockActionPreview(command)
} else {
blurContainer()
navigateToBlockActionPreview(command)
}
}
}
is Command.CloseKeyboard -> {
hideSoftInput()
}
@ -1139,31 +1119,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
}
}
private fun blurContainer() {
try {
Blurry.with(context)
.radius(12)
.sampling(6)
.onto(root)
} catch (e: Exception) {
Timber.e(e, "Blurry exception")
}
}
private fun navigateToBlockActionPreview(command: Command.OpenActionBar) {
childFragmentManager.beginTransaction()
.add(
R.id.root,
BlockActionToolbarFactory.newInstance(
block = command.block,
dimensions = command.dimensions
),
null
)
.addToBackStack(null)
.commit()
}
private fun render(state: ViewState) {
when (state) {
is ViewState.Success -> {
@ -1950,11 +1905,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
vm.onDownloadClicked()
}
override fun onDismissBlockActionToolbar() {
Blurry.delete(root)
vm.onDismissBlockActionMenu(childFragmentManager.backStackEntryCount > 0)
}
override fun onTextValueChanged(ctx: Id, text: String, objectId: Id, relationId: Id) {
vm.onRelationTextValueChanged(
ctx = ctx,
@ -2427,8 +2377,6 @@ open class EditorFragment : NavigationFragment(R.layout.fragment_editor),
interface OnFragmentInteractionListener {
fun onAddMarkupLinkClicked(blockId: String, link: String, range: IntRange)
fun onRemoveMarkupLinkClicked(blockId: String, range: IntRange)
fun onBlockActionClicked(id: String, action: ActionItemType)
fun onDismissBlockActionToolbar()
fun onAddBookmarkUrlClicked(target: String, url: String)
fun onExitToDesktopClicked()
fun onSetRelationKeyClicked(blockId: Id, key: Id)

View file

@ -1,600 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.OvershootInterpolator
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.core.view.doOnLayout
import androidx.fragment.app.Fragment
import androidx.transition.*
import com.anytypeio.anytype.BuildConfig
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.toSpannable
import com.anytypeio.anytype.core_ui.extensions.addVerticalDivider
import com.anytypeio.anytype.core_ui.extensions.color
import com.anytypeio.anytype.core_ui.extensions.drawable
import com.anytypeio.anytype.core_ui.widgets.BlockActionBarItem
import com.anytypeio.anytype.core_ui.widgets.text.MentionSpan
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.PopupExtensions
import com.anytypeio.anytype.presentation.editor.editor.BlockDimensions
import com.anytypeio.anytype.presentation.editor.editor.Markup
import com.anytypeio.anytype.presentation.editor.editor.ThemeColor
import com.anytypeio.anytype.presentation.editor.editor.actions.ActionItemType
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.ui.editor.OnFragmentInteractionListener
import kotlinx.android.synthetic.main.action_toolbar.*
import timber.log.Timber
import kotlin.math.abs
@Deprecated("Legacy")
abstract class BlockActionToolbar : Fragment() {
companion object {
const val ARG_BLOCK = "arg.block"
const val ARG_BLOCK_DIMENSIONS = "arg.block.dimensions"
const val ANIM_DURATION = 300L
const val DEFAULT_MARGIN = 0
const val INTERPOLATOR_OVERSHOOT_TENSION = 1.6f
}
abstract fun initUi(view: View, colorView: ImageView? = null, backgroundView: ImageView? = null)
abstract fun getBlock(): BlockView
abstract fun blockLayout(): Int
private var actionClick: (ActionItemType) -> Unit = {}
private var actionToolbarSize = 0
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.action_toolbar, container, false)
view.findViewById<FrameLayout>(R.id.block_container).apply {
addView(inflater.inflate(blockLayout(), this, false))
}
setOnBackPressedCallback()
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
actionClick = { actionType: ActionItemType ->
(parentFragment as? OnFragmentInteractionListener)?.onBlockActionClicked(
getBlock().id,
actionType
)
}
container.setOnClickListener {
(parentFragment as? OnFragmentInteractionListener)?.onDismissBlockActionToolbar()
}
when (val block = getBlock()) {
is BlockView.Title.Basic -> addButtons(view, ACTIONS.TEXT)
is BlockView.Title.Profile -> addButtons(view, ACTIONS.TEXT)
is BlockView.Text.Paragraph -> addButtons(view, ACTIONS.TEXT)
is BlockView.Text.Header.One -> addButtons(view, ACTIONS.TEXT)
is BlockView.Text.Header.Two -> addButtons(view, ACTIONS.TEXT)
is BlockView.Text.Header.Three -> addButtons(view, ACTIONS.TEXT)
is BlockView.Text.Highlight -> addButtons(view, ACTIONS.TEXT)
is BlockView.Code -> addButtons(view, ACTIONS.CODE)
is BlockView.Text.Checkbox -> {
if (block.isChecked) {
addButtons(view, ACTIONS.CHECKBOX_CHECKED)
} else {
addButtons(view, ACTIONS.TEXT)
}
}
is BlockView.Text.Bulleted -> addButtons(view, ACTIONS.TEXT)
is BlockView.Text.Numbered -> addButtons(view, ACTIONS.TEXT)
is BlockView.Text.Toggle -> addButtons(view, ACTIONS.TEXT)
is BlockView.Media.File -> addButtons(view, ACTIONS.FILE)
is BlockView.Upload.File -> addButtons(view, ACTIONS.FILE)
is BlockView.MediaPlaceholder.File -> addButtons(view, ACTIONS.FILE)
is BlockView.Error.File -> addButtons(view, ACTIONS.FILE)
is BlockView.Media.Video -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.Upload.Video -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.MediaPlaceholder.Video -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.Error.Video -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.LinkToObject.Default -> addButtons(view, ACTIONS.PAGE)
is BlockView.DividerLine -> addButtons(view, ACTIONS.DIVIDER)
is BlockView.DividerDots -> addButtons(view, ACTIONS.DIVIDER)
is BlockView.MediaPlaceholder.Bookmark -> addButtons(view, ACTIONS.BOOKMARK)
is BlockView.Media.Bookmark -> addButtons(view, ACTIONS.BOOKMARK)
is BlockView.Error.Bookmark -> addButtons(view, ACTIONS.BOOKMARK)
is BlockView.Media.Picture -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.MediaPlaceholder.Picture -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.Error.Picture -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.Upload.Picture -> addButtons(view, ACTIONS.VIDEO_PICTURE)
is BlockView.Relation.Related -> addButtons(view, ACTIONS.RELATION)
is BlockView.Relation.Placeholder -> addButtons(view, ACTIONS.RELATION_PLACEHOLDER)
}
if (BuildConfig.DEBUG) {
log(getBlock())
}
}
private fun addButtons(view: View, actions: List<ActionItemType>) =
with(action_container) {
var colorView: ImageView? = null
var backgroundView: ImageView? = null
actions.forEach { type ->
when (type) {
ActionItemType.Divider -> {
val height = resources.getDimensionPixelSize(R.dimen.default_toolbar_action_item_divider_height)
actionToolbarSize += height
addVerticalDivider(
height = height,
alpha = 1.0f,
color = context.color(R.color.light_grayish)
)
}
ActionItemType.DividerExtended -> {
val height = resources.getDimensionPixelSize(R.dimen.default_toolbar_action_item_divider_extended_height)
actionToolbarSize += height
addVerticalDivider(
height = height,
alpha = 1.0f,
color = context.color(R.color.light_grayish)
)
}
else -> {
actionToolbarSize += resources.getDimensionPixelSize(R.dimen.default_toolbar_action_item_height)
addView(
createActionBarItem(
type = type,
context = requireContext(),
actionClick = actionClick
)
)
}
}
}
initUi(
view = view,
backgroundView = backgroundView,
colorView = colorView
)
}
private fun setOnBackPressedCallback() {
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner,
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
(parentFragment as? OnFragmentInteractionListener)?.onDismissBlockActionToolbar()
}
})
}
private fun setBlockTextColor(content: TextView, color: String) {
if (color.isNotEmpty()) {
content.setTextColor(
ThemeColor.values().first { value ->
value.title == color
}.text
)
} else {
content.setTextColor(ThemeColor.DEFAULT.text)
}
}
private fun setBlockBackgroundColor(root: View, color: String? = null) {
if (!color.isNullOrEmpty()) {
root.setBackgroundColor(
ThemeColor.values().first { value ->
value.title == color
}.background
)
} else {
root.background = null
}
}
private fun setActionBarItemColor(item: ImageView, color: String) {
val colorRes = ThemeColor.values().first { value ->
value.title == color
}.text
if (colorRes != ThemeColor.DEFAULT.text) {
item.setImageDrawable(requireContext().drawable(R.drawable.ic_action_background))
item.setColorFilter(colorRes)
}
}
private fun setActionBarItemBackgroundColor(item: ImageView, color: String) {
val colorRes = ThemeColor.values().first { value ->
value.title == color
}.background
if (colorRes != ThemeColor.DEFAULT.background) {
item.setImageDrawable(requireContext().drawable(R.drawable.ic_action_background))
item.setColorFilter(colorRes)
}
}
fun processTextColor(
textView: TextView, colorImage: ImageView?, color: String?,
imageView: ImageView? = null
) =
color?.let {
setBlockTextColor(content = textView, color = it)
colorImage?.let { imageView ->
setActionBarItemColor(
item = imageView,
color = it
)
}
imageView?.setColorFilter(
ThemeColor.values().first { value ->
value.title == it
}.text
)
}
fun processBackgroundColor(root: View, bgImage: ImageView?, color: String?) {
setBlockBackgroundColor(root = root, color = color)
if (color != null) {
bgImage?.let {
setActionBarItemBackgroundColor(
item = it,
color = color
)
}
}
}
fun setBlockText(content: TextInputWidget, text: String, markup: Markup, textColor: Int) =
when (markup.marks.isEmpty()) {
true -> content.setText(text)
false -> setBlockSpannableText(content, markup, textColor)
}
private fun setBlockSpannableText(content: TextInputWidget, markup: Markup, textColor: Int) =
when (markup.marks.any { it is Markup.Mark.Mention }) {
true -> setSpannableWithMention(content, markup, textColor)
false -> setSpannable(content, markup, textColor)
}
private fun setSpannable(content: TextInputWidget, markup: Markup, textColor: Int) {
content.setText(markup.toSpannable(textColor = textColor), TextView.BufferType.SPANNABLE)
}
private fun setSpannableWithMention(content: TextInputWidget, markup: Markup, textColor: Int) {
with(content) {
val sizes = getMentionImageSizeAndPadding()
setText(
markup.toSpannable(
context = context,
mentionImageSize = sizes.first,
mentionImagePadding = sizes.second,
click = {},
onImageReady = { param -> refreshMentionSpan(content, param) },
textColor = textColor
),
TextView.BufferType.SPANNABLE
)
}
}
private fun refreshMentionSpan(content: TextInputWidget, param: String) {
content.text?.let { editable ->
val spans = editable.getSpans(
0,
editable.length,
MentionSpan::class.java
)
spans.forEach { span ->
if (span.param == param) {
editable.setSpan(
span,
editable.getSpanStart(span),
editable.getSpanEnd(span),
Markup.MENTION_SPANNABLE_FLAG
)
}
}
}
}
open fun getMentionImageSizeAndPadding(): Pair<Int, Int> =
Pair(
first = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_size_default),
second = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_padding_default)
)
private fun createActionBarItem(
type: ActionItemType,
context: Context,
actionClick: (ActionItemType) -> Unit
): BlockActionBarItem = BlockActionBarItem(context = context).apply {
setTypeAndClick(
itemType = type,
clickListener = { actionClick(it) }
)
}
private fun log(blockView: BlockView) {
Timber.d("ActionBar, open block: $blockView")
}
open fun getBlockPaddingTop(): Int {
return resources.getDimensionPixelOffset(R.dimen.action_toolbar_block_padding_top)
}
open fun getBlockPaddingBottom(): Int {
return resources.getDimensionPixelOffset(R.dimen.action_toolbar_block_padding_bottom)
}
private fun getUpdatedBlockDimensions(): BlockDimensions {
val blockPaddingTop = getBlockPaddingTop()
val blockPaddingBottom = getBlockPaddingBottom()
val dimensions: BlockDimensions = arguments?.getParcelable(ARG_BLOCK_DIMENSIONS)!!
return dimensions.copy(
top = dimensions.top - blockPaddingTop,
bottom = dimensions.bottom + blockPaddingTop,
height = dimensions.height + blockPaddingTop + blockPaddingBottom
)
}
private fun createStartSet() : ConstraintSet = ConstraintSet().apply {
clone(requireContext(), R.layout.action_toolbar)
setScaleX(R.id.block_container, 1f)
setScaleY(R.id.block_container, 1f)
setVisibility(R.id.card, View.INVISIBLE)
setScaleX(R.id.card, 0.3f)
setScaleY(R.id.card, 0.3f)
}
private fun createEndSet(): ConstraintSet = ConstraintSet().apply {
clone(requireContext(), R.layout.action_toolbar)
setScaleX(R.id.block_container, 1f)
setScaleY(R.id.block_container, 1f)
setVisibility(R.id.card, View.VISIBLE)
setScaleX(R.id.card, 1f)
setScaleY(R.id.card, 1f)
}
private fun createTransitionSet() = TransitionSet().apply {
addTransition(ChangeBounds())
addTransition(ChangeTransform())
addTransition(Fade(Visibility.MODE_IN))
duration = ANIM_DURATION
interpolator = OvershootInterpolator(INTERPOLATOR_OVERSHOOT_TENSION)
ordering = TransitionSet.ORDERING_TOGETHER
}
fun setConstraints() {
container.doOnLayout {
val blockDimensions = getUpdatedBlockDimensions()
val barMarginBottom =
resources.getDimensionPixelOffset(R.dimen.action_toolbar_bar_margin_bottom)
val barMarginTop =
resources.getDimensionPixelOffset(R.dimen.action_toolbar_bar_margin_top)
val screenDimensions = PopupExtensions.calculateRectInWindow(container)
val anchorView = BlockActionToolbarHelper.getAnchorView(
screenTop = screenDimensions.top,
screenBottom = screenDimensions.bottom,
blockTop = blockDimensions.top,
blockBottom = blockDimensions.bottom,
barHeight = actionToolbarSize,
barMarginBottom = barMarginBottom,
barMarginTop = barMarginTop,
blockHeight = blockDimensions.height
)
val startSet = createStartSet()
val endSet = createEndSet()
val blockId = R.id.block_container
val containerId = R.id.container
val barId = R.id.card
when (anchorView) {
BlockActionToolbarHelper.AnchorView.ACTION_BAR -> {
with(startSet) {
if (blockDimensions.bottom < screenDimensions.bottom) {
val blockMargin = screenDimensions.bottom - blockDimensions.bottom
connect(blockId, BOTTOM, containerId, BOTTOM, blockMargin)
} else {
connect(blockId, BOTTOM, containerId, BOTTOM, DEFAULT_MARGIN)
val translationY =
(blockDimensions.bottom - screenDimensions.bottom).toFloat()
setTranslationY(blockId, translationY)
}
connect(barId, TOP, blockId, BOTTOM, barMarginTop)
}
with(endSet) {
connect(blockId, BOTTOM, barId, TOP, barMarginTop)
connect(barId, BOTTOM, containerId, BOTTOM, barMarginBottom)
}
}
BlockActionToolbarHelper.AnchorView.BLOCK_GRAVITY_TOP -> {
with (startSet) {
connect(blockId, TOP, containerId, TOP, DEFAULT_MARGIN)
val translationY =
(abs(blockDimensions.top) + screenDimensions.top).toFloat()
setTranslationY(blockId, -translationY)
connect(barId, TOP, blockId, BOTTOM, barMarginTop)
}
with (endSet) {
connect(blockId, TOP, containerId, TOP, barMarginTop)
connect(barId, TOP, blockId, BOTTOM, barMarginTop)
}
}
BlockActionToolbarHelper.AnchorView.BLOCK -> {
with (startSet) {
val blockMargin = blockDimensions.top - screenDimensions.top
connect(blockId, TOP, containerId, TOP, blockMargin)
connect(barId, TOP, blockId, BOTTOM, barMarginTop)
}
with(endSet) {
val blockMargin = blockDimensions.top - screenDimensions.top
connect(blockId, TOP, containerId, TOP, blockMargin)
connect(barId, TOP, blockId, BOTTOM, barMarginTop)
}
}
}
startSet.applyTo(container)
container.post {
TransitionManager.beginDelayedTransition(container, createTransitionSet())
endSet.applyTo(container)
}
}
}
object ACTIONS {
val PAGE = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM
)
val PAGE_ARCHIVE = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.SAM
)
val TEXT = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.TurnIntoPage,
ActionItemType.Divider,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM,
ActionItemType.DividerExtended,
ActionItemType.Style
)
val CHECKBOX_CHECKED = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.TurnIntoPage,
ActionItemType.Divider,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM,
ActionItemType.DividerExtended,
ActionItemType.Style
)
val VIDEO_PICTURE = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.Download,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM,
)
val FILE = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.Download,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM
)
val BOOKMARK = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM
)
val CODE = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.TurnIntoPage,
ActionItemType.Divider,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM,
ActionItemType.DividerExtended,
ActionItemType.Style
)
val DIVIDER = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.SAM
)
val RELATION_PLACEHOLDER = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.SAM
)
val RELATION = listOf(
ActionItemType.AddBelow,
ActionItemType.DividerExtended,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.SAM,
ActionItemType.DividerExtended,
ActionItemType.Style
)
}
}

View file

@ -1,309 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import androidx.core.os.bundleOf
import com.anytypeio.anytype.presentation.editor.editor.BlockDimensions
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types
@Deprecated("Legacy")
object BlockActionToolbarFactory {
fun newInstance(block: BlockView, dimensions: BlockDimensions) = when (block) {
is BlockView.Text.Paragraph -> newInstance(block, dimensions)
is BlockView.Text.Header.One -> newInstance(block, dimensions)
is BlockView.Text.Header.Two -> newInstance(block, dimensions)
is BlockView.Text.Header.Three -> newInstance(block, dimensions)
is BlockView.Text.Highlight -> newInstance(block, dimensions)
is BlockView.Text.Checkbox -> newInstance(block, dimensions)
is BlockView.Text.Bulleted -> newInstance(block, dimensions)
is BlockView.Text.Numbered -> newInstance(block, dimensions)
is BlockView.Text.Toggle -> newInstance(block, dimensions)
is BlockView.Code -> newInstance(block, dimensions)
is BlockView.Media.File -> newInstance(block, dimensions)
is BlockView.Upload.File -> newInstance(block, dimensions)
is BlockView.MediaPlaceholder.File -> newInstance(block, dimensions)
is BlockView.Error.File -> newInstance(block, dimensions)
is BlockView.Media.Video -> newInstance(block, dimensions)
is BlockView.Upload.Video -> newInstance(block, dimensions)
is BlockView.MediaPlaceholder.Video -> newInstance(block, dimensions)
is BlockView.Error.Video -> newInstance(block, dimensions)
is BlockView.LinkToObject.Default -> newInstance(block, dimensions)
is BlockView.DividerLine -> newInstance(block, dimensions)
is BlockView.DividerDots -> newInstance(block, dimensions)
is BlockView.MediaPlaceholder.Bookmark -> newInstance(block, dimensions)
is BlockView.Media.Bookmark -> newInstance(block, dimensions)
is BlockView.Error.Bookmark -> newInstance(block, dimensions)
is BlockView.Media.Picture -> newInstance(block, dimensions)
is BlockView.MediaPlaceholder.Picture -> newInstance(block, dimensions)
is BlockView.Error.Picture -> newInstance(block, dimensions)
is BlockView.Upload.Picture -> newInstance(block, dimensions)
is BlockView.Title.Basic -> TODO()
is BlockView.Title.Profile -> TODO()
is BlockView.Title.Archive -> TODO()
is BlockView.Title.Todo -> TODO()
is BlockView.Relation.Placeholder -> newInstance(block, dimensions)
is BlockView.Relation.Related -> newInstance(block, dimensions)
is BlockView.Description -> TODO()
is BlockView.FeaturedRelation -> TODO()
is BlockView.Unsupported -> TODO()
is BlockView.Latex -> TODO()
is BlockView.LinkToObject.Archived -> TODO()
is BlockView.LinkToObject.Deleted -> TODO()
}
fun newInstance(
block: BlockView.Relation.Related,
dimensions: BlockDimensions
) = when (block.getViewType()) {
Types.HOLDER_RELATION_DEFAULT -> RelationDefaultActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
Types.HOLDER_RELATION_STATUS -> RelationStatusActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
Types.HOLDER_RELATION_TAGS -> RelationTagActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
Types.HOLDER_RELATION_OBJECT -> RelationObjectActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
Types.HOLDER_RELATION_FILE -> RelationFileActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
else -> throw IllegalArgumentException("Wrong BlockView.Relation type :${block.getViewType()}")
}
fun newInstance(
block: BlockView.Relation.Placeholder,
dimensions: BlockDimensions
): RelationPlaceholderActionToolbar =
RelationPlaceholderActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(block: BlockView.LinkToObject.Default, dimensions: BlockDimensions): PageBlockActionToolbar =
PageBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Paragraph,
dimensions: BlockDimensions
): ParagraphBlockActionToolbar =
ParagraphBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Header.One,
dimensions: BlockDimensions
): HeaderOneBlockActionToolbar =
HeaderOneBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Header.Two,
dimensions: BlockDimensions
): HeaderTwoBlockActionToolbar =
HeaderTwoBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Header.Three,
dimensions: BlockDimensions
): HeaderThreeBlockActionToolbar =
HeaderThreeBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Error,
dimensions: BlockDimensions
): ErrorActionToolbar =
ErrorActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Checkbox,
dimensions: BlockDimensions
): CheckBoxBlockActionToolbar =
CheckBoxBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(block: BlockView.Code, dimensions: BlockDimensions): CodeBlockActionToolbar =
CodeBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Highlight,
dimensions: BlockDimensions
): HighlightBlockActionToolbar =
HighlightBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Numbered,
dimensions: BlockDimensions
): NumberedBlockActionToolbar =
NumberedBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Toggle,
dimensions: BlockDimensions
): ToggleBlockActionToolbar =
ToggleBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Text.Bulleted,
dimensions: BlockDimensions
): BulletedBlockActionToolbar =
BulletedBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Media.File,
dimensions: BlockDimensions
): FileBlockActionToolbar =
FileBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.MediaPlaceholder,
dimensions: BlockDimensions
): PlaceholderActionToolbar =
PlaceholderActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Upload,
dimensions: BlockDimensions
): UploadActionToolbar =
UploadActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Media.Picture,
dimensions: BlockDimensions
): PictureBlockActionToolbar =
PictureBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Media.Video,
dimensions: BlockDimensions
): VideoBlockActionToolbar =
VideoBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(block: BlockView.DividerLine, dimensions: BlockDimensions): DividerLineBlockActionToolbar =
DividerLineBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(block: BlockView.DividerDots, dimensions: BlockDimensions): DividerDotsBlockActionToolbar =
DividerDotsBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
fun newInstance(
block: BlockView.Media.Bookmark,
dimensions: BlockDimensions
): BookmarkBlockActionToolbar =
BookmarkBlockActionToolbar().apply {
arguments = bundleOf(
BlockActionToolbar.ARG_BLOCK to block,
BlockActionToolbar.ARG_BLOCK_DIMENSIONS to dimensions
)
}
}

View file

@ -1,86 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
object BlockActionToolbarHelper {
enum class BlockVisibility {
FULL, // block is fully visible
BOTTOM_OUTSIDE, // we can see only top of the block
TOP_OUTSIDE, // we can see only bottom of the block
TOP_BOTTOM_OUTSIDE // block top and bottom are off the screen
}
/**
* Positioning in action toolbar
* @property ACTION_BAR, positioning action bar at the bottom, block at the top
* @property BLOCK_GRAVITY_TOP, draw block at the most top position, then action bar at the bottom
* @property BLOCK, draw block at exact start coordinates, then action bar at the bottom
*/
enum class AnchorView {
ACTION_BAR,
BLOCK_GRAVITY_TOP,
BLOCK
}
fun blockVisibilityState(
screenTop: Int,
screenBottom: Int,
blockTop: Int,
blockBottom: Int
): BlockVisibility =
when (blockTop > screenTop) {
true -> {
when (blockBottom < screenBottom) {
true -> BlockVisibility.FULL
false -> BlockVisibility.BOTTOM_OUTSIDE
}
}
false -> {
when (blockBottom < screenBottom) {
true -> BlockVisibility.TOP_OUTSIDE
false -> BlockVisibility.TOP_BOTTOM_OUTSIDE
}
}
}
fun canShowBlockAtTheBottom(
blockBottom: Int,
barHeight: Int,
screenBottom: Int,
barMarginTop: Int,
barMarginBottom: Int
): Boolean = blockBottom + barHeight + barMarginTop + barMarginBottom < screenBottom
fun getAnchorView(
screenTop: Int,
screenBottom: Int,
blockTop: Int,
blockBottom: Int,
blockHeight: Int,
barHeight: Int,
barMarginTop: Int,
barMarginBottom: Int
): AnchorView = when (blockVisibilityState(screenTop, screenBottom, blockTop, blockBottom)) {
BlockVisibility.FULL -> {
when (canShowBlockAtTheBottom(
blockBottom = blockBottom,
barHeight = barHeight,
screenBottom = screenBottom,
barMarginTop = barMarginTop,
barMarginBottom = barMarginBottom
)) {
true -> AnchorView.BLOCK
false -> AnchorView.ACTION_BAR
}
}
BlockVisibility.BOTTOM_OUTSIDE -> AnchorView.ACTION_BAR
BlockVisibility.TOP_OUTSIDE -> {
when (screenTop + blockHeight + barHeight + barMarginTop + barMarginBottom < screenBottom) {
true -> AnchorView.BLOCK_GRAVITY_TOP
false -> AnchorView.ACTION_BAR
}
}
BlockVisibility.TOP_BOTTOM_OUTSIDE -> AnchorView.ACTION_BAR
}
}

View file

@ -1,76 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.bumptech.glide.Glide
class BookmarkBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Media.Bookmark
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout(): Int = R.layout.item_block_bookmark
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
initBookmark(view)
setConstraints()
}
override fun getBlockPaddingTop(): Int = 0
override fun getBlockPaddingBottom(): Int = 0
private fun initBookmark(view: View) {
val item = block
view.findViewById<TextView>(R.id.bookmarkTitle).apply {
text = item.title
}
view.findViewById<TextView>(R.id.bookmarkDescription).apply {
text = item.description
}
view.findViewById<TextView>(R.id.bookmarkUrl).apply {
text = item.url
}
item.imageUrl?.let { url ->
view.findViewById<ImageView>(R.id.bookmarkImage).apply {
Glide.with(this)
.load(url)
.into(this)
}
}
item.faviconUrl?.let { url ->
view.findViewById<ImageView>(R.id.bookmarkLogo).apply {
Glide.with(this)
.load(url)
.into(this)
}
}
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
leftMargin = 0
topMargin = 0
bottomMargin = 0
rightMargin = 0
}
setPadding(0, 0, 0, 0)
}
view.findViewById<FrameLayout>(R.id.block_container)
.setPadding(
resources.getDimensionPixelOffset(R.dimen.dp_12),
resources.getDimensionPixelOffset(R.dimen.dp_6),
resources.getDimensionPixelOffset(R.dimen.dp_12),
resources.getDimensionPixelOffset(R.dimen.dp_6))
}
}

View file

@ -1,41 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class BulletedBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Bulleted
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_bulleted_preview
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<TextInputWidget>(R.id.bulletedListContent).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color,
imageView = view.findViewById(R.id.bullet)
)
}
processBackgroundColor(
root = view.findViewById(R.id.root),
color = block.backgroundColor,
bgImage = backgroundView
)
setConstraints()
}
}

View file

@ -1,43 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.extensions.color
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class CheckBoxBlockActionToolbar : BlockActionToolbar() {
val block: BlockView.Text.Checkbox
get() = arguments?.getParcelable(ARG_BLOCK) ?: throw IllegalStateException()
override fun blockLayout() = R.layout.item_block_checkbox_preview
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<TextInputWidget>(R.id.checkboxContent).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
if (block.isChecked) {
setTextColor(requireContext().color(R.color.checkbox_state_checked))
} else {
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
}
view.findViewById<ImageView>(R.id.checkboxIcon).apply {
isActivated = block.isChecked
}
processBackgroundColor(
root = view.findViewById(R.id.root),
color = block.backgroundColor,
bgImage = backgroundView
)
setConstraints()
}
}

View file

@ -1,51 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.ThemeColorCode
import com.anytypeio.anytype.core_ui.widgets.text.CodeTextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class CodeBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Code
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_code_snippet
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
leftMargin = 0
rightMargin = 0
}
}
view.findViewById<CodeTextInputWidget>(R.id.snippet).apply {
enableReadMode()
setText(block.text)
}
view.findViewById<LinearLayout>(R.id.snippetContainer).apply {
if (block.backgroundColor != null) {
val value =
ThemeColorCode.values().find { value -> value.title == block.backgroundColor }
if (value != null) {
(background as? GradientDrawable)?.setColor(value.background)
}
}
}
setConstraints()
}
}

View file

@ -1,39 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class DividerLineBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.DividerLine
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_divider_line
}
class DividerDotsBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.DividerDots
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_divider_dots
}

View file

@ -1,299 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.Manifest
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.provider.MediaStore
import android.view.View
import android.view.View.OVER_SCROLL_NEVER
import android.view.animation.OvershootInterpolator
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import com.anytypeio.anytype.R
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.analytics.base.EventsDictionary
import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_utils.ext.arg
import com.anytypeio.anytype.core_utils.ext.parsePath
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.core_utils.ui.BaseFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.emojifier.Emojifier
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_CHOOSE_EMOJI
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_CHOOSE_RANDOM_EMOJI
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_CHOOSE_UPLOAD_PHOTO
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter.Companion.OPTION_REMOVE
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuDivider
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModel
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModel.Contract
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModel.ViewState
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModelFactory
import com.anytypeio.anytype.ui.editor.modals.ObjectIconPickerFragment
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import kotlinx.android.synthetic.main.action_toolbar_page_icon.*
import timber.log.Timber
import javax.inject.Inject
@Deprecated("To be deleted")
class DocumentIconActionMenuFragment : BaseFragment(R.layout.action_toolbar_page_icon),
Observer<ViewState> {
private val ctx get() = arg<Id>(ARG_CONTEXT_ID_KEY)
private val target: String
get() = requireArguments()
.getString(ARG_TARGET_ID_KEY)
?: throw IllegalStateException(MISSING_TARGET_ERROR)
@Inject
lateinit var factory: DocumentIconActionMenuViewModelFactory
@Inject
lateinit var analytics: Analytics
private val vm by viewModels<DocumentIconActionMenuViewModel> { factory }
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() }
setIcon()
setupLogoTranslation()
setupAdapter()
showMenuWithAnimation()
}
private fun setIcon() {
arguments?.getString(EMOJI_KEY)?.let { unicode ->
try {
Glide
.with(emojiIconImage)
.load(Emojifier.uri(unicode))
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(emojiIconImage)
} catch (e: Throwable) {
Timber.e(e, "Error while setting emoji icon for: $unicode")
}
}
arguments?.getString(IMAGE_KEY)?.let { url ->
Glide
.with(icon)
.load(url)
.centerInside()
.circleCrop()
.into(imageIcon)
}
}
private fun setupLogoTranslation() {
val y = arguments?.getFloat(Y_KEY)
if (y != null && y != 0.0f) {
val delta = y - icon.y
icon.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)
overScrollMode = OVER_SCROLL_NEVER
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()
ObjectIconPickerFragment.new(
context = target,
target = target
).show(manager, null)
}
lifecycleScope.sendEvent(
analytics = analytics,
eventName = EventsDictionary.POPUP_CHOOSE_EMOJI
)
}
OPTION_REMOVE -> {
vm.onEvent(
Contract.Event.OnRemoveEmojiSelected(
context = target,
target = target
)
)
lifecycleScope.sendEvent(
analytics = analytics,
eventName = EventsDictionary.BTN_REMOVE_EMOJI
)
}
OPTION_CHOOSE_RANDOM_EMOJI -> {
vm.onEvent(
Contract.Event.OnSetRandomEmojiClicked(
context = target,
target = target
)
)
lifecycleScope.sendEvent(
analytics = analytics,
eventName = EventsDictionary.BTN_RANDOM_EMOJI
)
}
OPTION_CHOOSE_UPLOAD_PHOTO -> {
proceedWithImagePick()
lifecycleScope.sendEvent(
analytics = analytics,
eventName = EventsDictionary.BTN_UPLOAD_PHOTO
)
}
else -> toast("Not implemented")
}
}
}
}
override fun onChanged(state: ViewState) {
when (state) {
is ViewState.Exit -> exit()
is ViewState.Error -> toast(state.message)
is ViewState.Loading -> toast(getString(R.string.loading))
is ViewState.Uploading -> progress.visible()
}
}
private fun proceedWithImagePick() {
if (!hasExternalStoragePermission())
requestExternalStoragePermission()
else
openGallery()
}
private fun requestExternalStoragePermission() {
requestPermissions(
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_PERMISSION_CODE
)
}
private fun hasExternalStoragePermission() = ContextCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
).let { result -> result == PackageManager.PERMISSION_GRANTED }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == SELECT_IMAGE_CODE) {
data?.data?.let { uri ->
try {
val path = uri.parsePath(requireContext())
vm.onEvent(
Contract.Event.OnImagePickedFromGallery(
context = target,
path = path
)
)
} catch (e: Exception) {
Timber.e(COULD_NOT_PARSE_PATH_ERROR)
toast(COULD_NOT_PARSE_PATH_ERROR)
}
}
}
}
private fun exit() {
parentFragment?.childFragmentManager?.popBackStack()
}
private fun openGallery() {
try {
Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.INTERNAL_CONTENT_URI
).let { intent ->
startActivityForResult(intent, SELECT_IMAGE_CODE)
}
} catch (e: Exception) {
Timber.e(e, "Failed to open gallery")
toast("Failed to open gallery. Please, try again later.")
}
}
override fun injectDependencies() {
componentManager().documentIconActionMenuComponent.get(ctx).inject(this)
}
override fun releaseDependencies() {
componentManager().documentIconActionMenuComponent.release(ctx)
}
companion object {
fun new(
y: Float?,
emoji: String?,
image: String?,
target: String,
ctx: Id
): DocumentIconActionMenuFragment = DocumentIconActionMenuFragment().apply {
arguments = bundleOf(
Y_KEY to y,
EMOJI_KEY to emoji,
IMAGE_KEY to image,
ARG_TARGET_ID_KEY to target,
ARG_CONTEXT_ID_KEY to ctx
)
}
private const val SELECT_IMAGE_CODE = 1
private const val REQUEST_PERMISSION_CODE = 2
private const val Y_KEY = "y"
private const val EMOJI_KEY = "emoji"
private const val IMAGE_KEY = "image_key"
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 ARG_CONTEXT_ID_KEY = "arg.picker.target.id"
private const val MISSING_TARGET_ERROR = "Missing target id"
private const val COULD_NOT_PARSE_PATH_ERROR = "Could not parse path to your image"
}
}

View file

@ -1,55 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_BOOKMARK_ERROR
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_ERROR
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PICTURE_ERROR
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO_ERROR
class ErrorActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Error
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
if (block.getViewType() == HOLDER_BOOKMARK_ERROR) {
initBookmarkError(view)
}
setConstraints()
}
private fun initBookmarkError(view: View) {
val item = block as BlockView.Error.Bookmark
view.findViewById<TextView>(R.id.errorBookmarkUrl).apply {
text = item.url
}
view.findViewById<FrameLayout>(R.id.bookmarkErrorRoot)
.updateLayoutParams<FrameLayout.LayoutParams> {
this.apply {
rightMargin = 0
}
}
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int =
when (block.getViewType()) {
HOLDER_FILE_ERROR -> R.layout.item_block_file_error_preview
HOLDER_BOOKMARK_ERROR -> R.layout.item_block_bookmark_error
HOLDER_VIDEO_ERROR -> R.layout.item_block_video_error_preview
HOLDER_PICTURE_ERROR -> R.layout.item_block_picture_error_preview
else -> R.layout.item_block_file_error_preview
}
}

View file

@ -1,79 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.text.SpannableString
import android.text.format.Formatter
import android.text.style.ForegroundColorSpan
import android.text.style.RelativeSizeSpan
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.extensions.color
import com.anytypeio.anytype.core_ui.extensions.getMimeIcon
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.Markup
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class FileBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Media.File
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_file
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<ConstraintLayout>(R.id.root)
.updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
leftMargin = 0
rightMargin = 0
}
initFile(view)
}
private fun initFile(view: View) {
val item = block
view.findViewById<TextInputWidget>(R.id.filename).apply {
enableReadMode()
val name = block.name
val blockSize = block.size
if (blockSize != null && name != null) {
val size = Formatter.formatFileSize(context, blockSize)
val spannable = SpannableString("${item.name} $size")
val start = name.length + 2
val end = name.length + 2 + size.length
spannable.setSpan(
RelativeSizeSpan(0.87f),
start,
end,
Markup.DEFAULT_SPANNABLE_FLAG
)
spannable.setSpan(
ForegroundColorSpan(context.color(com.anytypeio.anytype.core_ui.R.color.block_file_size_text_color)),
start,
end,
Markup.DEFAULT_SPANNABLE_FLAG
)
setText(spannable, TextView.BufferType.SPANNABLE)
} else {
setText(item.name)
}
}
view.findViewById<ImageView>(R.id.fileIcon).apply {
val mimeIcon = item.mime.getMimeIcon(item.name)
setImageResource(mimeIcon)
}
setConstraints()
}
}

View file

@ -1,53 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class HeaderOneBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Header.One
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_header_one
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
setPadding(0,0,0,0)
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
}
processBackgroundColor(
root = this,
color = block.backgroundColor,
bgImage = backgroundView
)
}
view.findViewById<TextInputWidget>(R.id.headerOne).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
setConstraints()
}
override fun getMentionImageSizeAndPadding(): Pair<Int, Int> = Pair(
first = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_size_header_one),
second = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_padding_header_one)
)
}

View file

@ -1,53 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class HeaderThreeBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Header.Three
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_header_three
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
}
setPadding(0, 0, 0, 0)
processBackgroundColor(
root = this,
color = block.backgroundColor,
bgImage = backgroundView
)
}
view.findViewById<TextInputWidget>(R.id.headerThree).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
setConstraints()
}
override fun getMentionImageSizeAndPadding(): Pair<Int, Int> = Pair(
first = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_size_header_three),
second = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_padding_default)
)
}

View file

@ -1,53 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class HeaderTwoBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Header.Two
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_header_two
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
}
setPadding(0, 0, 0, 0)
processBackgroundColor(
root = this,
color = block.backgroundColor,
bgImage = backgroundView
)
}
view.findViewById<TextInputWidget>(R.id.headerTwo).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
setConstraints()
}
override fun getMentionImageSizeAndPadding(): Pair<Int, Int> = Pair(
first = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_size_header_two),
second = resources.getDimensionPixelSize(com.anytypeio.anytype.core_ui.R.dimen.mention_span_image_padding_header_two)
)
}

View file

@ -1,40 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class HighlightBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Highlight
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_highlight_preview
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<TextInputWidget>(R.id.highlightContent).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
processBackgroundColor(
root = view.findViewById(R.id.root),
color = block.backgroundColor,
bgImage = backgroundView
)
setConstraints()
}
}

View file

@ -1,55 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.core_utils.ext.addDot
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class NumberedBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Numbered
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_numbered_preview
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<TextView>(R.id.number).apply {
gravity = when (block.number) {
in 1..19 -> Gravity.CENTER_HORIZONTAL
else -> Gravity.START
}
text = block.number.addDot()
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
view.findViewById<TextInputWidget>(R.id.numberedListContent).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
processBackgroundColor(
root = view.findViewById(R.id.root),
color = block.backgroundColor,
bgImage = backgroundView
)
setConstraints()
}
}

View file

@ -1,35 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
@Deprecated("Legacy")
class PageBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.LinkToObject.Default
lateinit var emoji: ImageView
lateinit var image: ImageView
lateinit var title: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_page_preview
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
image = view.findViewById(R.id.linkImage)
emoji = view.findViewById(R.id.linkEmoji)
title = view.findViewById(R.id.pageTitle)
title.text = if (block.text.isNullOrEmpty()) getString(R.string.untitled) else block.text
setConstraints()
}
}

View file

@ -1,52 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class ParagraphBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Paragraph
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_text
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
leftMargin = 0
rightMargin = 0
}
setPadding(0,0,0,0)
}
view.findViewById<TextInputWidget>(R.id.textContent).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color
)
}
processBackgroundColor(
root = view.findViewById(R.id.root),
color = block.backgroundColor,
bgImage = backgroundView
)
setConstraints()
}
}

View file

@ -1,29 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.bumptech.glide.Glide
class PictureBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Media.Picture
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_picture_preview
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
val item = block
view.findViewById<ImageView>(R.id.image).apply {
Glide.with(this).load(item.url).into(this)
}
setConstraints()
}
}

View file

@ -1,46 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.FrameLayout.LayoutParams
import android.widget.ImageView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_BOOKMARK_PLACEHOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_PLACEHOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PICTURE_PLACEHOLDER
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO_PLACEHOLDER
class PlaceholderActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.MediaPlaceholder
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() =
when (block.getViewType()) {
HOLDER_PICTURE_PLACEHOLDER -> R.layout.item_block_picture_placeholder
HOLDER_VIDEO_PLACEHOLDER -> R.layout.item_block_video_placeholder
HOLDER_FILE_PLACEHOLDER -> R.layout.item_block_file_placeholder
HOLDER_BOOKMARK_PLACEHOLDER -> R.layout.item_block_bookmark_placeholder
else -> R.layout.item_block_picture_placeholder
}
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root)
.updateLayoutParams<LayoutParams> {
topMargin = 0
bottomMargin = 0
leftMargin = 0
rightMargin = 0
}
setConstraints()
}
}

View file

@ -1,257 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.ColorStateList
import android.os.Bundle
import android.provider.MediaStore
import android.view.View
import android.view.View.OVER_SCROLL_NEVER
import android.view.animation.OvershootInterpolator
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Id
import com.anytypeio.anytype.core_models.Url
import com.anytypeio.anytype.core_ui.extensions.avatarColor
import com.anytypeio.anytype.core_utils.ext.arg
import com.anytypeio.anytype.core_utils.ext.firstDigitByHash
import com.anytypeio.anytype.core_utils.ext.parsePath
import com.anytypeio.anytype.core_utils.ext.toast
import com.anytypeio.anytype.core_utils.ui.BaseFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuAdapter
import com.anytypeio.anytype.library_page_icon_picker_widget.ui.ActionMenuDivider
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModel
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModel.ViewState
import com.anytypeio.anytype.presentation.editor.picker.DocumentIconActionMenuViewModelFactory
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.action_toolbar_profile_icon.*
import timber.log.Timber
import javax.inject.Inject
class ProfileIconActionMenuFragment : BaseFragment(R.layout.action_toolbar_profile_icon),
Observer<ViewState> {
private val ctx get() = arg<Id>(ARG_CONTEXT_ID_KEY)
/**
* avatar image url
*/
private val image: Url?
get() = arguments?.getString(IMAGE_KEY)
/**
* user name
*/
private val name: String?
get() = arguments?.getString(NAME_KEY)
/**
* target (profile) id
*/
private val target: Id
get() = requireArguments()
.getString(ARG_TARGET_ID_KEY)
?: throw IllegalStateException(MISSING_TARGET_ERROR)
@Inject
lateinit var factory: DocumentIconActionMenuViewModelFactory
private val vm : DocumentIconActionMenuViewModel by viewModels { factory }
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
vm.state.observe(viewLifecycleOwner, this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initialize()
}
override fun onChanged(state: ViewState) {
when (state) {
is ViewState.Exit -> exit()
is ViewState.Error -> toast(state.message)
is ViewState.Loading -> toast(getString(R.string.loading))
}
}
private fun initialize() {
container.setOnClickListener { exit() }
setIcon()
setupLogoTranslation()
setupAdapter()
showMenuWithAnimation()
}
private fun setIcon() {
image?.let { url ->
Glide
.with(icon)
.load(url)
.centerInside()
.circleCrop()
.into(imageIcon)
} ?: apply {
imageText.text = name?.firstOrNull().toString()
val pos = name?.firstDigitByHash() ?: 0
icon.backgroundTintList = ColorStateList.valueOf(requireContext().avatarColor(pos))
imageIcon.setImageDrawable(null)
}
}
private fun setupLogoTranslation() {
val y = arguments?.getFloat(Y_KEY)
if (y != null && y != 0.0f) {
val delta = y - icon.y
icon.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)
overScrollMode = OVER_SCROLL_NEVER
adapter = ActionMenuAdapter(
options = intArrayOf(
ActionMenuAdapter.OPTION_CHOOSE_UPLOAD_PHOTO,
ActionMenuAdapter.OPTION_REMOVE
)
) { option ->
when (option) {
ActionMenuAdapter.OPTION_REMOVE -> vm.onEvent(
DocumentIconActionMenuViewModel.Contract.Event.OnRemoveEmojiSelected(
context = target,
target = target
)
)
ActionMenuAdapter.OPTION_CHOOSE_UPLOAD_PHOTO -> {
proceedWithImagePick()
}
else -> toast("Not implemented")
}
}
}
}
private fun proceedWithImagePick() {
if (!hasExternalStoragePermission())
requestExternalStoragePermission()
else
openGallery()
}
private fun requestExternalStoragePermission() {
requestPermissions(
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_PERMISSION_CODE
)
}
private fun openGallery() {
Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.INTERNAL_CONTENT_URI
).let { intent ->
startActivityForResult(intent, SELECT_IMAGE_CODE)
}
}
private fun hasExternalStoragePermission() = ContextCompat.checkSelfPermission(
requireActivity(),
Manifest.permission.WRITE_EXTERNAL_STORAGE
).let { result -> result == PackageManager.PERMISSION_GRANTED }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == SELECT_IMAGE_CODE) {
try {
data?.data?.let { uri ->
val path = uri.parsePath(requireContext())
vm.onEvent(
DocumentIconActionMenuViewModel.Contract.Event.OnImagePickedFromGallery(
context = target,
path = path
)
)
}
} catch (e: Exception) {
Timber.e(e, PARSE_PATH_ERROR)
toast(PARSE_PATH_ERROR)
}
}
}
override fun injectDependencies() {
componentManager().documentIconActionMenuComponent.get(ctx).inject(this)
}
override fun releaseDependencies() {
componentManager().documentIconActionMenuComponent.release(ctx)
}
private fun exit() {
parentFragment?.childFragmentManager?.popBackStack()
}
companion object {
fun new(
y: Float?,
image: String?,
name: String?,
target: String,
ctx: Id
): ProfileIconActionMenuFragment = ProfileIconActionMenuFragment().apply {
arguments = bundleOf(
Y_KEY to y,
IMAGE_KEY to image,
NAME_KEY to name,
ARG_TARGET_ID_KEY to target,
ARG_CONTEXT_ID_KEY to ctx
)
}
private const val SELECT_IMAGE_CODE = 1
private const val REQUEST_PERMISSION_CODE = 2
private const val Y_KEY = "y"
private const val IMAGE_KEY = "image_key"
private const val NAME_KEY = "name_key"
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 ARG_CONTEXT_ID_KEY = "arg.picker.target.context"
private const val MISSING_TARGET_ERROR = "Missing target id"
private const val PARSE_PATH_ERROR = "Failed to parse path for image"
}
}

View file

@ -1,261 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.extensions.color
import com.anytypeio.anytype.core_ui.widgets.GridCellFileItem
import com.anytypeio.anytype.core_ui.widgets.RelationObjectItem
import com.anytypeio.anytype.core_ui.widgets.text.TagWidget
import com.anytypeio.anytype.core_utils.ext.dimen
import com.anytypeio.anytype.core_utils.ext.visible
import com.anytypeio.anytype.presentation.editor.editor.ThemeColor
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.relations.DocumentRelationView
import com.anytypeio.anytype.presentation.sets.model.ObjectView
class RelationDefaultActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Relation.Related
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
}
setPadding(0, 0, 0, 0)
processBackgroundColor(
root = this,
color = block.background,
bgImage = backgroundView
)
}
view.findViewById<ViewGroup>(R.id.content).apply {
val paddingStart = context.dimen(R.dimen.default_document_content_padding_start)
val paddingEnd = context.dimen(R.dimen.default_document_content_padding_end)
updatePadding(left = paddingStart.toInt(), right = paddingEnd.toInt())
}
val item = block.view as DocumentRelationView.Default
view.findViewById<TextView>(R.id.tvRelationTitle).text = item.name
view.findViewById<TextView>(R.id.tvRelationValue).text = item.value
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_relation_default
}
class RelationStatusActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Relation.Related
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
}
setPadding(0, 0, 0, 0)
processBackgroundColor(
root = this,
color = block.background,
bgImage = backgroundView
)
}
view.findViewById<ViewGroup>(R.id.content).apply {
val paddingStart = context.dimen(R.dimen.default_document_content_padding_start)
val paddingEnd = context.dimen(R.dimen.default_document_content_padding_end)
updatePadding(left = paddingStart.toInt(), right = paddingEnd.toInt())
}
val item = block.view as DocumentRelationView.Status
view.findViewById<TextView>(R.id.tvRelationTitle).text = item.name
view.findViewById<TextView>(R.id.tvRelationValue).apply {
if (item.status.isNotEmpty()) {
val status = item.status.first()
text = status.status
val color = ThemeColor.values().find { v -> v.title == status.color }
if (color != null) {
setTextColor(color.text)
} else {
setTextColor(context.color(R.color.default_filter_status_text_color))
}
} else {
text = null
}
}
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_relation_status
}
class RelationTagActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Relation.Related
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
}
setPadding(0, 0, 0, 0)
processBackgroundColor(
root = this,
color = block.background,
bgImage = backgroundView
)
}
view.findViewById<ViewGroup>(R.id.content).apply {
val paddingStart = context.dimen(R.dimen.default_document_content_padding_start)
val paddingEnd = context.dimen(R.dimen.default_document_content_padding_end)
updatePadding(left = paddingStart.toInt(), right = paddingEnd.toInt())
}
val item = block.view as DocumentRelationView.Tags
view.findViewById<TextView>(R.id.tvRelationTitle).text = item.name
item.tags.forEachIndexed { index, tag ->
when (index) {
0 -> view.findViewById<TagWidget>(R.id.tag0).apply { setup(tag.tag, tag.color) }
1 -> view.findViewById<TagWidget>(R.id.tag1).apply { setup(tag.tag, tag.color) }
2 -> view.findViewById<TagWidget>(R.id.tag2).apply { setup(tag.tag, tag.color) }
3 -> view.findViewById<TagWidget>(R.id.tag3).apply { setup(tag.tag, tag.color) }
4 -> view.findViewById<TagWidget>(R.id.tag4).apply { setup(tag.tag, tag.color) }
5 -> view.findViewById<TagWidget>(R.id.tag5).apply { setup(tag.tag, tag.color) }
}
}
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_relation_tag
}
class RelationObjectActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Relation.Related
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
}
setPadding(0, 0, 0, 0)
processBackgroundColor(
root = this,
color = block.background,
bgImage = backgroundView
)
}
view.findViewById<ViewGroup>(R.id.content).apply {
val paddingStart = context.dimen(R.dimen.default_document_content_padding_start)
val paddingEnd = context.dimen(R.dimen.default_document_content_padding_end)
updatePadding(left = paddingStart.toInt(), right = paddingEnd.toInt())
}
val item = block.view as DocumentRelationView.Object
view.findViewById<TextView>(R.id.tvRelationTitle).text = item.name
item.objects.forEachIndexed { index, objectView ->
if (objectView is ObjectView.Default) {
when (index) {
0 -> view.findViewById<RelationObjectItem>(R.id.obj0).apply {
visible()
setup(objectView.name, objectView.icon)
}
1 -> view.findViewById<RelationObjectItem>(R.id.obj1).apply {
visible()
setup(objectView.name, objectView.icon)
}
2 -> view.findViewById<RelationObjectItem>(R.id.obj2).apply {
visible()
setup(objectView.name, objectView.icon)
}
3 -> view.findViewById<RelationObjectItem>(R.id.obj3).apply {
visible()
setup(objectView.name, objectView.icon)
}
}
}
}
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_relation_object
}
class RelationFileActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Relation.Related
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
}
setPadding(0, 0, 0, 0)
processBackgroundColor(
root = this,
color = block.background,
bgImage = backgroundView
)
}
view.findViewById<ViewGroup>(R.id.content).apply {
val paddingStart = context.dimen(R.dimen.default_document_content_padding_start)
val paddingEnd = context.dimen(R.dimen.default_document_content_padding_end)
updatePadding(left = paddingStart.toInt(), right = paddingEnd.toInt())
}
val item = block.view as DocumentRelationView.File
view.findViewById<TextView>(R.id.tvRelationTitle).text = item.name
item.files.forEachIndexed { index, file ->
when (index) {
0 -> view.findViewById<GridCellFileItem>(R.id.file0).apply {
setup(name = file.name, mime = file.mime)
}
1 -> view.findViewById<GridCellFileItem>(R.id.file1).apply {
setup(name = file.name, mime = file.mime)
}
2 -> view.findViewById<GridCellFileItem>(R.id.file2).apply {
setup(name = file.name, mime = file.mime)
}
}
}
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_relation_file
}

View file

@ -1,36 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.view.updateLayoutParams
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class RelationPlaceholderActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Relation.Placeholder
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<FrameLayout>(R.id.root).apply {
updateLayoutParams<FrameLayout.LayoutParams> {
topMargin = 0
bottomMargin = 0
leftMargin = 0
rightMargin = 0
}
setPadding(0, 0, 0, 0)
}
setConstraints()
}
override fun getBlock(): BlockView = block
override fun blockLayout(): Int = R.layout.item_block_relation_placeholder
}

View file

@ -1,47 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.common.getBlockTextColor
import com.anytypeio.anytype.core_ui.features.editor.holders.text.Toggle
import com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
class ToggleBlockActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Text.Toggle
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() = R.layout.item_block_toggle_preview
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
view.findViewById<TextInputWidget>(R.id.toggleContent).apply {
enableReadMode()
setBlockText(this, block.text, block, block.getBlockTextColor())
processTextColor(
textView = this,
colorImage = colorView,
color = block.color,
imageView = view.findViewById(R.id.toggle)
)
}
processBackgroundColor(
root = view.findViewById(R.id.root),
color = block.backgroundColor,
bgImage = backgroundView
)
view.findViewById<ImageView>(R.id.toggle).apply {
rotation =
if (block.toggled) Toggle.EXPANDED_ROTATION
else Toggle.COLLAPSED_ROTATION
}
setConstraints()
}
}

View file

@ -1,34 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_FILE_UPLOAD
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_PICTURE_UPLOAD
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO_UPLOAD
class UploadActionToolbar : BlockActionToolbar() {
lateinit var block: BlockView.Upload
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() =
when (block.getViewType()) {
HOLDER_PICTURE_UPLOAD -> R.layout.item_block_picture_uploading_preview
HOLDER_VIDEO_UPLOAD -> R.layout.item_block_video_uploading_preview
HOLDER_FILE_UPLOAD -> R.layout.item_block_file_uploading_preview
else -> R.layout.item_block_picture_uploading_preview
}
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
setConstraints()
}
}

View file

@ -1,62 +0,0 @@
package com.anytypeio.anytype.ui.editor.modals.actions
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.ImageView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.BuildConfig
import com.anytypeio.anytype.presentation.editor.editor.model.BlockView
import com.anytypeio.anytype.presentation.editor.editor.model.types.Types.HOLDER_VIDEO
import com.google.android.exoplayer2.SimpleExoPlayer
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.ui.PlayerView
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.util.Util
class VideoBlockActionToolbar : BlockActionToolbar() {
companion object {
const val SEEK_PREVIEW_POSITION = 1000L
}
lateinit var block: BlockView.Media.Video
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
block = arguments?.getParcelable(ARG_BLOCK)!!
}
override fun blockLayout() =
when (block.getViewType()) {
HOLDER_VIDEO -> R.layout.item_block_video_playback_off
else -> R.layout.item_block_video_uploading_preview
}
override fun getBlock(): BlockView = block
override fun initUi(view: View, colorView: ImageView?, backgroundView: ImageView?) {
when (block.getViewType()) {
HOLDER_VIDEO -> initVideo(view)
else -> Unit
}
}
private fun initVideo(view: View) {
val item = block
view.findViewById<PlayerView>(R.id.playerView).apply {
val player = SimpleExoPlayer.Builder(context).build()
val source = DefaultDataSourceFactory(
context,
Util.getUserAgent(context, BuildConfig.LIBRARY_PACKAGE_NAME)
)
val mediaSource =
ProgressiveMediaSource.Factory(source).createMediaSource(Uri.parse(item.url))
player.playWhenReady = false
player.seekTo(SEEK_PREVIEW_POSITION)
player.prepare(mediaSource, false, false)
this.player = player
}
setConstraints()
}
}

View file

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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:focusable="true"
android:clickable="true"
android:background="@color/anytype_shadow_main"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:id="@+id/card"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:cardCornerRadius="10dp"
android:layout_marginStart="48dp"
android:layout_marginEnd="48dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<LinearLayout
android:id="@+id/action_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:layout_height="200dp" />
</androidx.cardview.widget.CardView>
<FrameLayout
android:id="@+id/block_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:paddingTop="@dimen/action_toolbar_block_padding_top"
android:paddingBottom="@dimen/action_toolbar_block_padding_bottom"
android:background="@drawable/rounded_text_action_bg"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="307dp"
tools:layout_height="200dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,299 +0,0 @@
package com.anytypeio.anytype
import com.anytypeio.anytype.ui.editor.modals.actions.BlockActionToolbarHelper
import com.anytypeio.anytype.ui.editor.modals.actions.BlockActionToolbarHelper.blockVisibilityState
import com.anytypeio.anytype.ui.editor.modals.actions.BlockActionToolbarHelper.canShowBlockAtTheBottom
import com.anytypeio.anytype.ui.editor.modals.actions.BlockActionToolbarHelper.getAnchorView
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class ActionBarTest {
@Test
fun `action bar should be anchor view, when top and bottom are outside`() {
val screenTop = 0
val blockTop = -200
val screenBottom = 1000
val blockBottom = 1200
val blockHeight = 1400
val barHeight = 250
val barMarginTop = 49
val barMarginBottom = 20
val result = getAnchorView(
screenBottom = screenBottom,
screenTop = screenTop,
blockBottom = blockBottom,
blockTop = blockTop,
barMarginBottom = barMarginBottom,
barMarginTop = barMarginTop,
barHeight = barHeight,
blockHeight = blockHeight
)
val expected = BlockActionToolbarHelper.AnchorView.ACTION_BAR
assertEquals(expected = expected, actual = result)
}
@Test
fun `action bar should be anchor view, when only bottom visible and not enough space`() {
val screenTop = 0
val blockTop = -200
val screenBottom = 1000
val blockBottom = 800
val blockHeight = 1000
val barHeight = 250
val barMarginTop = 49
val barMarginBottom = 20
val result = getAnchorView(
screenBottom = screenBottom,
screenTop = screenTop,
blockBottom = blockBottom,
blockTop = blockTop,
barMarginBottom = barMarginBottom,
barMarginTop = barMarginTop,
barHeight = barHeight,
blockHeight = blockHeight
)
val expected = BlockActionToolbarHelper.AnchorView.ACTION_BAR
assertEquals(expected = expected, actual = result)
}
@Test
fun `block top gravity should be anchor view, when only bottom visible and enough space`() {
val screenTop = 0
val blockTop = -200
val screenBottom = 1000
val blockBottom = 300
val blockHeight = 500
val barHeight = 250
val barMarginTop = 49
val barMarginBottom = 20
val result = getAnchorView(
screenBottom = screenBottom,
screenTop = screenTop,
blockBottom = blockBottom,
blockTop = blockTop,
barMarginBottom = barMarginBottom,
barMarginTop = barMarginTop,
barHeight = barHeight,
blockHeight = blockHeight
)
val expected = BlockActionToolbarHelper.AnchorView.BLOCK_GRAVITY_TOP
assertEquals(expected = expected, actual = result)
}
@Test
fun `action bar should be anchor view, when only top visible`() {
val screenTop = 0
val blockTop = 800
val screenBottom = 1000
val blockBottom = 1300
val blockHeight = 500
val barHeight = 250
val barMarginTop = 49
val barMarginBottom = 20
val result = getAnchorView(
screenBottom = screenBottom,
screenTop = screenTop,
blockBottom = blockBottom,
blockTop = blockTop,
barMarginBottom = barMarginBottom,
barMarginTop = barMarginTop,
barHeight = barHeight,
blockHeight = blockHeight
)
val expected = BlockActionToolbarHelper.AnchorView.ACTION_BAR
assertEquals(expected = expected, actual = result)
}
@Test
fun `block should be anchor view, when full visible, and enough space`() {
val screenTop = 0
val blockTop = 100
val screenBottom = 1000
val blockBottom = 300
val blockHeight = 200
val barHeight = 250
val barMarginTop = 49
val barMarginBottom = 20
val result = getAnchorView(
screenBottom = screenBottom,
screenTop = screenTop,
blockBottom = blockBottom,
blockTop = blockTop,
barMarginBottom = barMarginBottom,
barMarginTop = barMarginTop,
barHeight = barHeight,
blockHeight = blockHeight
)
val expected = BlockActionToolbarHelper.AnchorView.BLOCK
assertEquals(expected = expected, actual = result)
}
@Test
fun `action bar should be anchor view, when full visible, and not enough space`() {
val screenTop = 0
val blockTop = 100
val screenBottom = 1000
val blockBottom = 800
val blockHeight = 700
val barHeight = 250
val barMarginTop = 49
val barMarginBottom = 20
val result = getAnchorView(
screenBottom = screenBottom,
screenTop = screenTop,
blockBottom = blockBottom,
blockTop = blockTop,
barMarginBottom = barMarginBottom,
barMarginTop = barMarginTop,
barHeight = barHeight,
blockHeight = blockHeight
)
val expected = BlockActionToolbarHelper.AnchorView.ACTION_BAR
assertEquals(expected = expected, actual = result)
}
@Test
fun `block visibility is FULL`() {
val screenTop = 0
val blockTop = 100
val screenBottom = 1000
val blockBottom = 300
val result = blockVisibilityState(screenTop, screenBottom, blockTop, blockBottom)
val expected = BlockActionToolbarHelper.BlockVisibility.FULL
assertEquals(expected = expected, actual = result)
}
@Test
fun `block visibility is TOP`() {
val screenTop = 0
val blockTop = 100
val screenBottom = 1000
val blockBottom = 1001
val result = blockVisibilityState(screenTop, screenBottom, blockTop, blockBottom)
val expected = BlockActionToolbarHelper.BlockVisibility.BOTTOM_OUTSIDE
assertEquals(expected = expected, actual = result)
}
@Test
fun `block visibility is BOTTOM`() {
val screenTop = 0
val blockTop = -1
val screenBottom = 1000
val blockBottom = 999
val result = blockVisibilityState(screenTop, screenBottom, blockTop, blockBottom)
val expected = BlockActionToolbarHelper.BlockVisibility.TOP_OUTSIDE
assertEquals(expected = expected, actual = result)
}
@Test
fun `block visibility is TOP_BOTTOM_OUTSIDE`() {
val screenTop = 0
val blockTop = -1
val screenBottom = 1000
val blockBottom = 1001
val result = blockVisibilityState(screenTop, screenBottom, blockTop, blockBottom)
val expected = BlockActionToolbarHelper.BlockVisibility.TOP_BOTTOM_OUTSIDE
assertEquals(expected = expected, actual = result)
}
@Test
fun `can show action bar at the blocks bottom`() {
val barHeight = 400
val barMarginTop = 80
val barMarginBottom = 20
val blockBottom = 499
val screenBottom = 1000
val result = canShowBlockAtTheBottom(
blockBottom = blockBottom,
barHeight = barHeight,
screenBottom = screenBottom,
barMarginTop = barMarginTop,
barMarginBottom = barMarginBottom
)
assertTrue(result)
}
@Test
fun `can't show action bar at the blocks bottom`() {
val barHeight = 400
val barMarginTop = 80
val barMarginBottom = 20
val blockBottom = 501
val screenBottom = 1000
val result = canShowBlockAtTheBottom(
blockBottom = blockBottom,
barHeight = barHeight,
screenBottom = screenBottom,
barMarginTop = barMarginTop,
barMarginBottom = barMarginBottom
)
assertFalse(result)
}
}

View file

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/dp_12"
android:paddingEnd="@dimen/dp_12">
<View
android:id="@+id/bulletIndent"
android:layout_width="0dp"
android:layout_height="0dp" />
<ImageView
android:id="@+id/bullet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:src="@drawable/ic_bulleted" />
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
android:id="@+id/bulletedListContent"
style="@style/BlockBulletContentStyle"
android:layout_marginStart="4dp"
android:gravity="center_vertical"
tools:text="@string/default_text_placeholder" />
</LinearLayout>

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/dp_12"
android:paddingEnd="@dimen/dp_12">
<ImageView
android:id="@+id/checkboxIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:contentDescription="@string/content_description_checkbox_pic"
android:src="@drawable/selector_block_checkbox" />
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
android:layout_marginStart="4dp"
android:id="@+id/checkboxContent"
style="@style/BlockCheckboxContentStyle"
tools:text="New front-end based on design" />
</LinearLayout>

View file

@ -1,60 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fileErrorPlaceholderRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_document_item_padding_start"
android:layout_marginTop="6dp"
android:layout_marginEnd="@dimen/default_document_item_padding_end"
android:layout_marginBottom="6dp"
android:background="@drawable/rectangle_block_media_background"
android:paddingTop="1dp"
android:paddingBottom="1dp">
<ImageView
android:id="@+id/icFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_file_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_file_light" />
<TextView
android:id="@+id/errorMessage"
style="@style/BlockVideoStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="24dp"
android:inputType="none"
android:text="@string/error_while_loading"
android:textColor="@android:color/holo_red_dark"
app:layout_constraintBottom_toBottomOf="@+id/icFile"
app:layout_constraintEnd_toStartOf="@+id/btnFileErrorMenu"
app:layout_constraintStart_toEndOf="@+id/icFile"
app:layout_constraintTop_toTopOf="@+id/icFile"
tools:text="@string/error_while_loading" />
<ImageView
android:id="@+id/btnFileErrorMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_block_more" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fileUploadingPlaceholderRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_document_item_padding_start"
android:layout_marginTop="6dp"
android:layout_marginEnd="@dimen/default_document_item_padding_end"
android:layout_marginBottom="6dp"
android:background="@drawable/rectangle_block_media_background"
android:paddingTop="1dp"
android:paddingBottom="1dp">
<ImageView
android:id="@+id/icFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_file_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_file_light" />
<TextView
android:id="@+id/editUrl"
style="@style/BlockVideoStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:inputType="none"
android:text="Loading, please wait"
android:textColor="#ACA996"
app:layout_constraintBottom_toBottomOf="@+id/icFile"
app:layout_constraintStart_toEndOf="@+id/icFile"
app:layout_constraintTop_toTopOf="@+id/icFile" />
<ImageView
android:id="@+id/icMore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_block_more" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/editUrl"
app:layout_constraintStart_toEndOf="@+id/editUrl"
app:layout_constraintTop_toTopOf="@+id/editUrl" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/root"
android:paddingTop="1dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
android:id="@+id/highlightContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/inter_regular"
android:textColor="@color/black"
android:textSize="17sp"
android:lineSpacingExtra="3sp"
android:background="@drawable/vertical_line"
android:layout_marginStart="24dp"
android:paddingStart="16dp"
android:paddingEnd="@dimen/dp_12"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/default_text_placeholder" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,29 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="@dimen/dp_12"
android:paddingEnd="@dimen/dp_12">
<TextView
android:id="@+id/number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:minWidth="@dimen/default_block_type_width"
android:textColor="@color/black"
android:textSize="15sp"
android:visibility="visible"
tools:text="19." />
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
android:id="@+id/numberedListContent"
style="@style/BlockNumberedContentStyle"
android:layout_marginStart="4dp"
android:hint="@string/hint_numbered_list"
tools:text="@string/default_text_placeholder" />
</LinearLayout>

View file

@ -1,58 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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:background="@drawable/item_block_multi_select_mode_selector"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/pageGuideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="0dp" />
<FrameLayout
android:id="@+id/pageIconContainer"
android:layout_width="24dp"
android:layout_height="24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/pageGuideline"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/pageIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@string/content_description_page_icon" />
<ImageView
android:id="@+id/linkImage"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/linkEmoji"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="center" />
</FrameLayout>
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
android:id="@+id/pageTitle"
style="@style/BlockPageContentStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@null"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/pageIconContainer"
app:layout_constraintTop_toTopOf="parent"
tools:text="Partnership terms" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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/pictureErrorRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_document_item_padding_start"
android:layout_marginTop="6dp"
android:layout_marginEnd="@dimen/default_document_item_padding_end"
android:layout_marginBottom="6dp"
android:background="@drawable/rectangle_block_media_background"
android:paddingTop="1dp"
android:paddingBottom="1dp">
<ImageView
android:id="@+id/icPicture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_file_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_file_light" />
<TextView
android:id="@+id/editUrl"
style="@style/BlockVideoStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="24dp"
android:inputType="none"
android:text="@string/error_while_loading"
tools:text="@string/error_while_loading"
android:textColor="@android:color/holo_red_dark"
app:layout_constraintBottom_toBottomOf="@+id/icPicture"
app:layout_constraintEnd_toStartOf="@+id/btnPicErrorMenu"
app:layout_constraintStart_toEndOf="@+id/icPicture"
app:layout_constraintTop_toTopOf="@+id/icPicture" />
<ImageView
android:id="@+id/btnPicErrorMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_block_more" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View file

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/pictureRootLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:paddingTop="1dp"
android:paddingBottom="1dp">
<ImageView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/block_with_a_picture"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/error_while_loading_picture"
android:textColor="@android:color/holo_red_dark"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="@+id/image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/image"
app:layout_constraintTop_toTopOf="@+id/image" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/pictureUploadRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_document_item_padding_start"
android:layout_marginTop="6dp"
android:layout_marginEnd="@dimen/default_document_item_padding_end"
android:layout_marginBottom="6dp"
android:background="@drawable/rectangle_block_media_background"
android:paddingTop="1dp"
android:paddingBottom="1dp">
<ImageView
android:id="@+id/icPicture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_file_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_file_light" />
<TextView
android:id="@+id/editUrl"
style="@style/BlockVideoStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:inputType="none"
android:text="Loading, please wait"
android:textColor="#ACA996"
app:layout_constraintBottom_toBottomOf="@+id/icPicture"
app:layout_constraintStart_toEndOf="@+id/icPicture"
app:layout_constraintTop_toTopOf="@+id/icPicture" />
<ImageView
android:id="@+id/btnPicUploadMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_block_more" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/editUrl"
app:layout_constraintStart_toEndOf="@+id/editUrl"
app:layout_constraintTop_toTopOf="@+id/editUrl" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View file

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/dp_12"
android:paddingEnd="@dimen/dp_12">
<ImageView
android:id="@+id/toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:background="@drawable/ic_block_toggle"
android:contentDescription="@string/content_description_toggle_icon"
app:layout_constraintStart_toEndOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent" />
<com.anytypeio.anytype.core_ui.widgets.text.TextInputWidget
android:layout_width="0dp"
android:id="@+id/toggleContent"
style="@style/ToggleContentStyle"
android:layout_marginStart="4dp"
android:textSize="15sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/toggle"
app:layout_constraintTop_toTopOf="parent"
tools:text="@string/default_text_placeholder" />
<TextView
android:id="@+id/togglePlaceholder"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:paddingBottom="3dp"
android:text="@string/empty_tap_to_create_new_block"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="@+id/toggleContent"
app:layout_constraintStart_toStartOf="@+id/toggleContent"
app:layout_constraintTop_toBottomOf="@+id/toggleContent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,59 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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/videoErrorRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_document_item_padding_start"
android:layout_marginTop="6dp"
android:layout_marginEnd="@dimen/default_document_item_padding_end"
android:layout_marginBottom="6dp"
android:background="@drawable/rectangle_block_media_background"
android:paddingTop="1dp"
android:paddingBottom="1dp">
<ImageView
android:id="@+id/icVideo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_file_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_video" />
<TextView
android:id="@+id/tvError"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="24dp"
android:text="@string/error_while_loading"
android:textColor="@android:color/holo_red_dark"
app:layout_constraintBottom_toBottomOf="@+id/icVideo"
app:layout_constraintEnd_toStartOf="@+id/btnVideoErrorMenu"
app:layout_constraintStart_toEndOf="@+id/icVideo"
app:layout_constraintTop_toTopOf="@+id/icVideo"
tools:text="@string/error_while_loading" />
<ImageView
android:id="@+id/btnVideoErrorMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_block_more" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View file

@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/videoUploadingPlaceholderRoot"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/default_document_item_padding_start"
android:layout_marginTop="6dp"
android:layout_marginEnd="@dimen/default_document_item_padding_end"
android:layout_marginBottom="6dp"
android:background="@drawable/rectangle_block_media_background"
android:paddingTop="1dp"
android:paddingBottom="1dp">
<ImageView
android:id="@+id/icVideo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginBottom="12dp"
android:contentDescription="@string/content_description_file_icon"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_video" />
<TextView
android:id="@+id/editUrl"
style="@style/BlockVideoStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="Loading, please wait"
android:textColor="#ACA996"
app:layout_constraintBottom_toBottomOf="@+id/icVideo"
app:layout_constraintStart_toEndOf="@+id/icVideo"
app:layout_constraintTop_toTopOf="@+id/icVideo" />
<ImageView
android:id="@+id/icMore"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_block_more" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/editUrl"
app:layout_constraintStart_toEndOf="@+id/editUrl"
app:layout_constraintTop_toTopOf="@+id/editUrl" />
</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

View file

@ -27,7 +27,6 @@ ext {
// Third party libraries
exoplayer_version = '2.14.1'
glide_version = '4.12.0'
blurry_version = '4.0.0'
shimmer_layout_version = "0.5.0"
photo_view_version = '2.3.0'
dagger_version = '2.36'
@ -111,7 +110,6 @@ ext {
androidAnnotations: "androidx.annotation:annotation:$appcompat_version",
betterLinkMovement: "me.saket:better-link-movement-method:$better_link_method_version",
emojiCompat: "androidx.emoji:emoji-appcompat:$emoji_compat_version",
blurry: "jp.wasabeef:blurry:$blurry_version",
photoView: "com.github.chrisbanes:PhotoView:$photo_view_version",
katex: "com.github.judemanutd:katexview:$katex_version",
glide: "com.github.bumptech.glide:glide:$glide_version",

View file

@ -1 +0,0 @@
/build

View file

@ -1,37 +0,0 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 29
buildToolsVersion '29.0.2'
defaultConfig {
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
testOptions {
unitTests {
includeAndroidResources = true
}
}
}
dependencies {
def applicationDependencies = rootProject.ext.mainApplication
def unitTestDependencies = rootProject.ext.unitTesting
implementation applicationDependencies.recyclerView
implementation applicationDependencies.cardView
testImplementation unitTestDependencies.robolectric
testImplementation unitTestDependencies.mockitoKotlin
testImplementation unitTestDependencies.junit
testImplementation unitTestDependencies.assertj
}

View file

@ -1,27 +0,0 @@
VERSION_NAME=1.6.6
VERSION_CODE=53
GROUP=com.github.woxthebox
POM_DESCRIPTION=Drag and drop to re-order items in a list, grid or board.
POM_URL=https://github.com/woxthebox/DragListView
POM_SCM_URL=scm:git@github.com:woxthebox/DragListView.git
POM_SCM_CONNECTION=scm:git@github.com:woxthebox/DragListView.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:woxthebox/DragListView.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=woxthebox
POM_DEVELOPER_NAME=Magnus Woxblom
POM_NAME=DragListView
POM_ARTIFACT_ID=draglistview
POM_PACKAGING=aar
SNAPSHOT_REPOSITORY_URL=https://oss.sonatype.org/content/repositories/snapshots
RELEASE_REPOSITORY_URL=https://oss.sonatype.org/service/local/staging/deploy/maven2
NEXUS_USERNAME=
NEXUS_PASSWORD=
signing.keyId=
signing.password=
signing.secretKeyRingFile=

View file

@ -1,112 +0,0 @@
/*
* Copyright 2013 Chris Banes
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
apply plugin: 'maven'
apply plugin: 'signing'
def isReleaseBuild() {
return VERSION_NAME.contains("SNAPSHOT") == false
}
def getReleaseRepositoryUrl() {
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
}
def getSnapshotRepositoryUrl() {
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
: "https://oss.sonatype.org/content/repositories/snapshots/"
}
def getRepositoryUsername() {
return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
}
def getRepositoryPassword() {
return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
}
afterEvaluate { project ->
uploadArchives {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
pom.groupId = GROUP
pom.artifactId = POM_ARTIFACT_ID
pom.version = VERSION_NAME
repository(url: getReleaseRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
snapshotRepository(url: getSnapshotRepositoryUrl()) {
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
}
pom.project {
name POM_NAME
packaging POM_PACKAGING
description POM_DESCRIPTION
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEV_CONNECTION
}
licenses {
license {
name POM_LICENCE_NAME
url POM_LICENCE_URL
distribution POM_LICENCE_DIST
}
}
developers {
developer {
id POM_DEVELOPER_ID
name POM_DEVELOPER_NAME
}
}
}
}
}
}
signing {
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
sign configurations.archives
}
//task androidJavadocs(type: Javadoc) {
//source = android.sourceSets.main.allJava
//}
//task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
//classifier = 'javadoc'
//from androidJavadocs.destinationDir
//}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.sourceFiles
}
artifacts {
archives androidSourcesJar
}
}

View file

@ -1,17 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\Wox\Programming\android-sdks/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.woxthebox.draglistview">
</manifest>

View file

@ -1,133 +0,0 @@
/*
* Copyright 2014 Magnus Woxblom
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.woxthebox.draglistview;
import android.content.Context;
import android.os.Handler;
class AutoScroller {
enum AutoScrollMode {
POSITION, COLUMN
}
enum ScrollDirection {
UP, DOWN, LEFT, RIGHT
}
interface AutoScrollListener {
void onAutoScrollPositionBy(int dx, int dy);
void onAutoScrollColumnBy(int columns);
}
private static final int SCROLL_SPEED_DP = 8;
private static final int AUTO_SCROLL_UPDATE_DELAY = 12;
private static final int COLUMN_SCROLL_UPDATE_DELAY = 1000;
private Handler mHandler = new Handler();
private AutoScrollListener mListener;
private boolean mIsAutoScrolling;
private int mScrollSpeed;
private long mLastScrollTime;
private AutoScrollMode mAutoScrollMode = AutoScrollMode.POSITION;
AutoScroller(Context context, AutoScrollListener listener) {
mListener = listener;
mScrollSpeed = (int) (context.getResources().getDisplayMetrics().density * SCROLL_SPEED_DP);
}
void setAutoScrollMode(AutoScrollMode autoScrollMode) {
mAutoScrollMode = autoScrollMode;
}
boolean isAutoScrolling() {
return mIsAutoScrolling;
}
void stopAutoScroll() {
mIsAutoScrolling = false;
}
void startAutoScroll(ScrollDirection direction) {
switch (direction) {
case UP:
startAutoScrollPositionBy(0, mScrollSpeed);
break;
case DOWN:
startAutoScrollPositionBy(0, -mScrollSpeed);
break;
case LEFT:
if (mAutoScrollMode == AutoScrollMode.POSITION) {
startAutoScrollPositionBy(mScrollSpeed, 0);
} else {
startAutoScrollColumnBy(1);
}
break;
case RIGHT:
if (mAutoScrollMode == AutoScrollMode.POSITION) {
startAutoScrollPositionBy(-mScrollSpeed, 0);
} else {
startAutoScrollColumnBy(-1);
}
break;
}
}
private void startAutoScrollPositionBy(int dx, int dy) {
if (!mIsAutoScrolling) {
mIsAutoScrolling = true;
autoScrollPositionBy(dx, dy);
}
}
private void autoScrollPositionBy(final int dx, final int dy) {
if (mIsAutoScrolling) {
mListener.onAutoScrollPositionBy(dx, dy);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
autoScrollPositionBy(dx, dy);
}
}, AUTO_SCROLL_UPDATE_DELAY);
}
}
private void startAutoScrollColumnBy(int columns) {
if (!mIsAutoScrolling) {
mIsAutoScrolling = true;
autoScrollColumnBy(columns);
}
}
private void autoScrollColumnBy(final int columns) {
if (mIsAutoScrolling) {
if (System.currentTimeMillis() - mLastScrollTime > COLUMN_SCROLL_UPDATE_DELAY) {
mListener.onAutoScrollColumnBy(columns);
mLastScrollTime = System.currentTimeMillis();
} else {
mListener.onAutoScrollColumnBy(0);
}
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
autoScrollColumnBy(columns);
}
}, AUTO_SCROLL_UPDATE_DELAY);
}
}
}

View file

@ -1,219 +0,0 @@
/*
* Copyright 2014 Magnus Woxblom
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.woxthebox.draglistview;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
public class DragItem {
protected static final int ANIMATION_DURATION = 250;
private View mDragView;
private View mRealDragView;
private float mOffsetX;
private float mOffsetY;
private float mPosX;
private float mPosY;
private float mPosTouchDx;
private float mPosTouchDy;
private float mAnimationDx;
private float mAnimationDy;
private boolean mCanDragHorizontally = true;
private boolean mSnapToTouch = true;
DragItem(Context context) {
mDragView = new View(context);
hide();
}
public DragItem(Context context, int layoutId) {
mDragView = View.inflate(context, layoutId, null);
hide();
}
public void onBindDragView(View clickedView, View dragView) {
Bitmap bitmap = Bitmap.createBitmap(clickedView.getWidth(), clickedView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
clickedView.draw(canvas);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
dragView.setBackground(new BitmapDrawable(clickedView.getResources(), bitmap));
} else {
//noinspection deprecation
dragView.setBackgroundDrawable(new BitmapDrawable(clickedView.getResources(), bitmap));
}
}
public void onMeasureDragView(View clickedView, View dragView) {
dragView.setLayoutParams(new FrameLayout.LayoutParams(clickedView.getMeasuredWidth(), clickedView.getMeasuredHeight()));
int widthSpec = View.MeasureSpec.makeMeasureSpec(clickedView.getMeasuredWidth(), View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(clickedView.getMeasuredHeight(), View.MeasureSpec.EXACTLY);
dragView.measure(widthSpec, heightSpec);
}
public void onStartDragAnimation(View dragView) {
}
public void onEndDragAnimation(View dragView) {
}
boolean canDragHorizontally() {
return mCanDragHorizontally;
}
void setCanDragHorizontally(boolean canDragHorizontally) {
mCanDragHorizontally = canDragHorizontally;
}
boolean isSnapToTouch() {
return mSnapToTouch;
}
protected void setSnapToTouch(boolean snapToTouch) {
mSnapToTouch = snapToTouch;
}
View getDragItemView() {
return mDragView;
}
View getRealDragView() {
return mRealDragView;
}
private void show() {
mDragView.setVisibility(View.VISIBLE);
}
void hide() {
mDragView.setVisibility(View.GONE);
mRealDragView = null;
}
boolean isDragging() {
return mDragView.getVisibility() == View.VISIBLE;
}
void startDrag(View startFromView, float touchX, float touchY) {
show();
mRealDragView = startFromView;
onBindDragView(startFromView, mDragView);
onMeasureDragView(startFromView, mDragView);
onStartDragAnimation(mDragView);
float startX = startFromView.getX() - (mDragView.getMeasuredWidth() - startFromView.getMeasuredWidth()) / 2 + mDragView
.getMeasuredWidth() / 2;
float startY = startFromView.getY() - (mDragView.getMeasuredHeight() - startFromView.getMeasuredHeight()) / 2 + mDragView
.getMeasuredHeight() / 2;
if (mSnapToTouch) {
mPosTouchDx = 0;
mPosTouchDy = 0;
setPosition(touchX, touchY);
setAnimationDx(startX - touchX);
setAnimationDY(startY - touchY);
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("AnimationDx", mAnimationDx, 0);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("AnimationDY", mAnimationDy, 0);
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(this, pvhX, pvhY);
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(ANIMATION_DURATION);
anim.start();
} else {
mPosTouchDx = startX - touchX;
mPosTouchDy = startY - touchY;
setPosition(touchX, touchY);
}
}
void endDrag(View endToView, AnimatorListenerAdapter listener) {
onEndDragAnimation(mDragView);
float endX = endToView.getX() - (mDragView.getMeasuredWidth() - endToView.getMeasuredWidth()) / 2 + mDragView
.getMeasuredWidth() / 2;
float endY = endToView.getY() - (mDragView.getMeasuredHeight() - endToView.getMeasuredHeight()) / 2 + mDragView
.getMeasuredHeight() / 2;
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("X", mPosX, endX);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("Y", mPosY, endY);
ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(this, pvhX, pvhY);
anim.setInterpolator(new DecelerateInterpolator());
anim.setDuration(ANIMATION_DURATION);
anim.addListener(listener);
anim.start();
}
@SuppressWarnings("WeakerAccess")
void setAnimationDx(float x) {
mAnimationDx = x;
updatePosition();
}
@SuppressWarnings("WeakerAccess")
void setAnimationDY(float y) {
mAnimationDy = y;
updatePosition();
}
@SuppressWarnings("unused")
void setX(float x) {
mPosX = x;
updatePosition();
}
@SuppressWarnings("unused")
void setY(float y) {
mPosY = y;
updatePosition();
}
float getX() {
return mPosX;
}
float getY() {
return mPosY;
}
void setPosition(float touchX, float touchY) {
mPosX = touchX + mPosTouchDx;
mPosY = touchY + mPosTouchDy;
updatePosition();
}
void setOffset(float offsetX, float offsetY) {
mOffsetX = offsetX;
mOffsetY = offsetY;
updatePosition();
}
private void updatePosition() {
if (mCanDragHorizontally) {
mDragView.setX(mPosX + mOffsetX + mAnimationDx - mDragView.getMeasuredWidth() / 2);
}
mDragView.setY(mPosY + mOffsetY + mAnimationDy - mDragView.getMeasuredHeight() / 2);
mDragView.invalidate();
}
}

View file

@ -1,237 +0,0 @@
/*
* Copyright 2014 Magnus Woxblom
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.woxthebox.draglistview;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import android.view.MotionEvent;
import android.view.View;
import java.util.Collections;
import java.util.List;
public abstract class DragItemAdapter<T, VH extends DragItemAdapter.ViewHolder> extends RecyclerView.Adapter<VH> {
interface DragStartCallback {
boolean startDrag(View itemView, long itemId);
boolean isDragging();
}
private DragStartCallback mDragStartCallback;
private long mDragItemId = RecyclerView.NO_ID;
private long mDropTargetId = RecyclerView.NO_ID;
protected List<T> mItemList;
/**
* @return a unique id for an item at the specific position.
*/
public abstract long getUniqueItemId(int position);
public DragItemAdapter() {
setHasStableIds(true);
}
public void setItemList(List<T> itemList) {
mItemList = itemList;
notifyDataSetChanged();
}
public List<T> getItemList() {
return mItemList;
}
public int getPositionForItem(T item) {
int count = getItemCount();
for (int i = 0; i < count; i++) {
if (mItemList.get(i) == item) {
return i;
}
}
return RecyclerView.NO_POSITION;
}
public Object removeItem(int pos) {
if (mItemList != null && mItemList.size() > pos && pos >= 0) {
Object item = mItemList.remove(pos);
notifyItemRemoved(pos);
return item;
}
return null;
}
public void addItem(int pos, T item) {
if (mItemList != null && mItemList.size() >= pos) {
mItemList.add(pos, item);
notifyItemInserted(pos);
}
}
public void changeItemPosition(int fromPos, int toPos) {
if (mItemList != null && mItemList.size() > fromPos && mItemList.size() > toPos) {
T item = mItemList.remove(fromPos);
mItemList.add(toPos, item);
notifyItemMoved(fromPos, toPos);
}
}
public void swapItems(int pos1, int pos2) {
if (mItemList != null && mItemList.size() > pos1 && mItemList.size() > pos2) {
Collections.swap(mItemList, pos1, pos2);
notifyDataSetChanged();
}
}
public int getPositionForItemId(long id) {
int count = getItemCount();
for (int i = 0; i < count; i++) {
if (id == getItemId(i)) {
return i;
}
}
return RecyclerView.NO_POSITION;
}
@Override
public final long getItemId(int position) {
return getUniqueItemId(position);
}
@Override
public int getItemCount() {
return mItemList == null ? 0 : mItemList.size();
}
@CallSuper
@Override
public void onBindViewHolder(@NonNull VH holder, int position) {
long itemId = getItemId(position);
holder.mItemId = itemId;
holder.itemView.setVisibility(mDragItemId == itemId ? View.INVISIBLE : View.VISIBLE);
holder.setDragStartCallback(mDragStartCallback);
}
@Override
public void onViewRecycled(@NonNull VH holder) {
super.onViewRecycled(holder);
holder.setDragStartCallback(null);
}
void setDragStartedListener(DragStartCallback dragStartedListener) {
mDragStartCallback = dragStartedListener;
}
void setDragItemId(long dragItemId) {
mDragItemId = dragItemId;
}
void setDropTargetId(long dropTargetId) {
mDropTargetId = dropTargetId;
}
public long getDropTargetId() {
return mDropTargetId;
}
public static abstract class ViewHolder extends RecyclerView.ViewHolder {
public View mGrabView;
public long mItemId;
private DragStartCallback mDragStartCallback;
public ViewHolder(final View itemView, int handleResId, boolean dragOnLongPress) {
super(itemView);
mGrabView = itemView.findViewById(handleResId);
if (dragOnLongPress) {
mGrabView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
if (mDragStartCallback == null) {
return false;
}
if (mDragStartCallback.startDrag(itemView, mItemId)) {
return true;
}
if (itemView == mGrabView) {
return onItemLongClicked(view);
}
return false;
}
});
} else {
mGrabView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
if (mDragStartCallback == null) {
return false;
}
if (event.getAction() == MotionEvent.ACTION_DOWN && mDragStartCallback.startDrag(itemView, mItemId)) {
return true;
}
if (!mDragStartCallback.isDragging() && itemView == mGrabView) {
return onItemTouch(view, event);
}
return false;
}
});
}
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClicked(view);
}
});
if (itemView != mGrabView) {
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
return onItemLongClicked(view);
}
});
itemView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
return onItemTouch(view, event);
}
});
}
}
public void setDragStartCallback(DragStartCallback dragStartedListener) {
mDragStartCallback = dragStartedListener;
}
public void onItemClicked(View view) {
}
public boolean onItemLongClicked(View view) {
return false;
}
public boolean onItemTouch(View view, MotionEvent event) {
return false;
}
}
}

View file

@ -1,534 +0,0 @@
/**
* Copyright 2014 Magnus Woxblom
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.woxthebox.draglistview;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
public class DragItemRecyclerView extends RecyclerView implements AutoScroller.AutoScrollListener {
public interface DragItemListener {
void onDragStarted(int itemPosition, float x, float y);
void onDragging(int itemPosition, float x, float y);
void onDragEnded(int newItemPosition);
}
public interface DragItemCallback {
boolean canDragItemAtPosition(int dragPosition);
boolean canDropItemAtPosition(int dropPosition);
}
private enum DragState {
DRAG_STARTED, DRAGGING, DRAG_ENDED
}
private AutoScroller mAutoScroller;
private DragItemListener mListener;
private DragItemCallback mDragCallback;
private DragState mDragState = DragState.DRAG_ENDED;
private DragItemAdapter mAdapter;
private DragItem mDragItem;
private Drawable mDropTargetBackgroundDrawable;
private Drawable mDropTargetForegroundDrawable;
private long mDragItemId = NO_ID;
private boolean mHoldChangePosition;
private int mDragItemPosition;
private int mTouchSlop;
private float mStartY;
private boolean mClipToPadding;
private boolean mCanNotDragAboveTop;
private boolean mCanNotDragBelowBottom;
private boolean mScrollingEnabled = true;
private boolean mDisableReorderWhenDragging;
private boolean mDragEnabled = true;
public DragItemRecyclerView(Context context) {
super(context);
init();
}
public DragItemRecyclerView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
init();
}
public DragItemRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
mAutoScroller = new AutoScroller(getContext(), this);
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
addItemDecoration(new ItemDecoration() {
@Override
public void onDraw(Canvas c, RecyclerView parent, State state) {
super.onDraw(c, parent, state);
drawDecoration(c, parent, mDropTargetBackgroundDrawable);
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, State state) {
super.onDrawOver(c, parent, state);
drawDecoration(c, parent, mDropTargetForegroundDrawable);
}
private void drawDecoration(Canvas c, RecyclerView parent, Drawable drawable) {
if (mAdapter == null || mAdapter.getDropTargetId() == NO_ID || drawable == null) {
return;
}
for (int i = 0; i < parent.getChildCount(); i++) {
View item = parent.getChildAt(i);
int pos = getChildAdapterPosition(item);
if (pos != NO_POSITION && mAdapter.getItemId(pos) == mAdapter.getDropTargetId()) {
drawable.setBounds(item.getLeft(), item.getTop(), item.getRight(), item.getBottom());
drawable.draw(c);
}
}
}
});
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (!mScrollingEnabled) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartY = event.getY();
break;
case MotionEvent.ACTION_MOVE:
final float diffY = Math.abs(event.getY() - mStartY);
if (diffY > mTouchSlop * 0.5) {
// Steal event from parent as we now only want to scroll in the list
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
}
return super.onInterceptTouchEvent(event);
}
void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
}
boolean isDragEnabled() {
return mDragEnabled;
}
void setCanNotDragAboveTopItem(boolean canNotDragAboveTop) {
mCanNotDragAboveTop = canNotDragAboveTop;
}
void setCanNotDragBelowBottomItem(boolean canNotDragBelowBottom) {
mCanNotDragBelowBottom = canNotDragBelowBottom;
}
void setScrollingEnabled(boolean scrollingEnabled) {
mScrollingEnabled = scrollingEnabled;
}
void setDisableReorderWhenDragging(boolean disableReorder) {
mDisableReorderWhenDragging = disableReorder;
}
public void setDropTargetDrawables(Drawable backgroundDrawable, Drawable foregroundDrawable) {
mDropTargetBackgroundDrawable = backgroundDrawable;
mDropTargetForegroundDrawable = foregroundDrawable;
}
void setDragItemListener(DragItemListener listener) {
mListener = listener;
}
void setDragItemCallback(DragItemCallback callback) {
mDragCallback = callback;
}
void setDragItem(DragItem dragItem) {
mDragItem = dragItem;
}
boolean isDragging() {
return mDragState != DragState.DRAG_ENDED;
}
long getDragItemId() {
return mDragItemId;
}
@Override
public void setClipToPadding(boolean clipToPadding) {
super.setClipToPadding(clipToPadding);
mClipToPadding = clipToPadding;
}
@Override
public void setAdapter(Adapter adapter) {
if (!isInEditMode()) {
if (!(adapter instanceof DragItemAdapter)) {
throw new RuntimeException("Adapter must extend DragItemAdapter");
}
if (!adapter.hasStableIds()) {
throw new RuntimeException("Adapter must have stable ids");
}
}
super.setAdapter(adapter);
mAdapter = (DragItemAdapter) adapter;
}
@Override
public void swapAdapter(Adapter adapter, boolean r) {
if (!isInEditMode()) {
if (!(adapter instanceof DragItemAdapter)) {
throw new RuntimeException("Adapter must extend DragItemAdapter");
}
if (!adapter.hasStableIds()) {
throw new RuntimeException("Adapter must have stable ids");
}
}
super.swapAdapter(adapter, r);
mAdapter = (DragItemAdapter) adapter;
}
@Override
public void setLayoutManager(LayoutManager layout) {
super.setLayoutManager(layout);
if (!(layout instanceof LinearLayoutManager)) {
throw new RuntimeException("Layout must be an instance of LinearLayoutManager");
}
}
@Override
public void onAutoScrollPositionBy(int dx, int dy) {
if (isDragging()) {
scrollBy(dx, dy);
updateDragPositionAndScroll();
} else {
mAutoScroller.stopAutoScroll();
}
}
@Override
public void onAutoScrollColumnBy(int columns) {
}
/**
* Returns the child view under the specific x,y coordinate.
* This method will take margins of the child into account when finding it.
*/
public View findChildView(float x, float y) {
final int count = getChildCount();
if (y <= 0 && count > 0) {
return getChildAt(0);
}
for (int i = count - 1; i >= 0; i--) {
final View child = getChildAt(i);
MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
if (x >= child.getLeft() - params.leftMargin && x <= child.getRight() + params.rightMargin
&& y >= child.getTop() - params.topMargin && y <= child.getBottom() + params.bottomMargin) {
return child;
}
}
return null;
}
private boolean shouldChangeItemPosition(int newPos) {
// Check if drag position is changed and valid and that we are not in a hold position state
if (mHoldChangePosition || mDragItemPosition == NO_POSITION || mDragItemPosition == newPos) {
return false;
}
// If we are not allowed to drag above top or bottom and new pos is 0 or item count then return false
if ((mCanNotDragAboveTop && newPos == 0) || (mCanNotDragBelowBottom && newPos == mAdapter.getItemCount() - 1)) {
return false;
}
// Check with callback if we are allowed to drop at this position
if (mDragCallback != null && !mDragCallback.canDropItemAtPosition(newPos)) {
return false;
}
return true;
}
private void updateDragPositionAndScroll() {
View view = findChildView(mDragItem.getX(), mDragItem.getY());
int newPos = getChildLayoutPosition(view);
if (newPos == NO_POSITION || view == null) {
return;
}
// If using a LinearLayoutManager and the new view has a bigger height we need to check if passing centerY as well.
// If not doing this extra check the bigger item will move back again when dragging slowly over it.
boolean linearLayoutManager = getLayoutManager() instanceof LinearLayoutManager && !(getLayoutManager() instanceof GridLayoutManager);
if (linearLayoutManager) {
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
int viewHeight = view.getMeasuredHeight() + params.topMargin + params.bottomMargin;
int viewCenterY = view.getTop() - params.topMargin + viewHeight / 2;
boolean dragDown = mDragItemPosition < getChildLayoutPosition(view);
boolean movedPassedCenterY = dragDown ? mDragItem.getY() > viewCenterY : mDragItem.getY() < viewCenterY;
// If new height is bigger then current and not passed centerY then reset back to current position
if (viewHeight > mDragItem.getDragItemView().getMeasuredHeight() && !movedPassedCenterY) {
newPos = mDragItemPosition;
}
}
LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager();
if (shouldChangeItemPosition(newPos)) {
if (mDisableReorderWhenDragging) {
mAdapter.setDropTargetId(mAdapter.getItemId(newPos));
mAdapter.notifyDataSetChanged();
} else {
int pos = layoutManager.findFirstVisibleItemPosition();
View posView = layoutManager.findViewByPosition(pos);
mAdapter.changeItemPosition(mDragItemPosition, newPos);
mDragItemPosition = newPos;
// Since notifyItemMoved scrolls the list we need to scroll back to where we were after the position change.
if (layoutManager.getOrientation() == LinearLayoutManager.VERTICAL) {
int topMargin = ((MarginLayoutParams) posView.getLayoutParams()).topMargin;
layoutManager.scrollToPositionWithOffset(pos, posView.getTop() - topMargin);
} else {
int leftMargin = ((MarginLayoutParams) posView.getLayoutParams()).leftMargin;
layoutManager.scrollToPositionWithOffset(pos, posView.getLeft() - leftMargin);
}
}
}
boolean lastItemReached = false;
boolean firstItemReached = false;
int top = mClipToPadding ? getPaddingTop() : 0;
int bottom = mClipToPadding ? getHeight() - getPaddingBottom() : getHeight();
int left = mClipToPadding ? getPaddingLeft() : 0;
int right = mClipToPadding ? getWidth() - getPaddingRight() : getWidth();
ViewHolder lastChild = findViewHolderForLayoutPosition(mAdapter.getItemCount() - 1);
ViewHolder firstChild = findViewHolderForLayoutPosition(0);
// Check if first or last item has been reached
if (layoutManager.getOrientation() == LinearLayoutManager.VERTICAL) {
if (lastChild != null && lastChild.itemView.getBottom() <= bottom) {
lastItemReached = true;
}
if (firstChild != null && firstChild.itemView.getTop() >= top) {
firstItemReached = true;
}
} else {
if (lastChild != null && lastChild.itemView.getRight() <= right) {
lastItemReached = true;
}
if (firstChild != null && firstChild.itemView.getLeft() >= left) {
firstItemReached = true;
}
}
// Start auto scroll if at the edge
if (layoutManager.getOrientation() == LinearLayoutManager.VERTICAL) {
if (mDragItem.getY() > getHeight() - view.getHeight() / 2 && !lastItemReached) {
mAutoScroller.startAutoScroll(AutoScroller.ScrollDirection.UP);
} else if (mDragItem.getY() < view.getHeight() / 2 && !firstItemReached) {
mAutoScroller.startAutoScroll(AutoScroller.ScrollDirection.DOWN);
} else {
mAutoScroller.stopAutoScroll();
}
} else {
if (mDragItem.getX() > getWidth() - view.getWidth() / 2 && !lastItemReached) {
mAutoScroller.startAutoScroll(AutoScroller.ScrollDirection.LEFT);
} else if (mDragItem.getX() < view.getWidth() / 2 && !firstItemReached) {
mAutoScroller.startAutoScroll(AutoScroller.ScrollDirection.RIGHT);
} else {
mAutoScroller.stopAutoScroll();
}
}
}
boolean startDrag(View itemView, long itemId, float x, float y) {
int dragItemPosition = mAdapter.getPositionForItemId(itemId);
if (!mDragEnabled || (mCanNotDragAboveTop && dragItemPosition == 0)
|| (mCanNotDragBelowBottom && dragItemPosition == mAdapter.getItemCount() - 1)) {
return false;
}
if (mDragCallback != null && !mDragCallback.canDragItemAtPosition(dragItemPosition)) {
return false;
}
// If a drag is starting the parent must always be allowed to intercept
getParent().requestDisallowInterceptTouchEvent(false);
mDragState = DragState.DRAG_STARTED;
mDragItemId = itemId;
mDragItem.startDrag(itemView, x, y);
mDragItemPosition = dragItemPosition;
updateDragPositionAndScroll();
mAdapter.setDragItemId(mDragItemId);
mAdapter.notifyDataSetChanged();
if (mListener != null) {
mListener.onDragStarted(mDragItemPosition, mDragItem.getX(), mDragItem.getY());
}
invalidate();
return true;
}
void onDragging(float x, float y) {
if (mDragState == DragState.DRAG_ENDED) {
return;
}
mDragState = DragState.DRAGGING;
mDragItemPosition = mAdapter.getPositionForItemId(mDragItemId);
mDragItem.setPosition(x, y);
if (!mAutoScroller.isAutoScrolling()) {
updateDragPositionAndScroll();
}
if (mListener != null) {
mListener.onDragging(mDragItemPosition, x, y);
}
invalidate();
}
void onDragEnded() {
// Need check because sometimes the framework calls drag end twice in a row
if (mDragState == DragState.DRAG_ENDED) {
return;
}
mAutoScroller.stopAutoScroll();
setEnabled(false);
if (mDisableReorderWhenDragging) {
int newPos = mAdapter.getPositionForItemId(mAdapter.getDropTargetId());
if (newPos != NO_POSITION) {
mAdapter.swapItems(mDragItemPosition, newPos);
mDragItemPosition = newPos;
}
mAdapter.setDropTargetId(NO_ID);
}
// Post so layout is done before we start end animation
post(new Runnable() {
@Override
public void run() {
// Sometimes the holder will be null if a holder has not yet been set for the position
final RecyclerView.ViewHolder holder = findViewHolderForAdapterPosition(mDragItemPosition);
if (holder != null) {
if (getItemAnimator() != null) {
getItemAnimator().endAnimation(holder);
}
mDragItem.endDrag(holder.itemView, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
holder.itemView.setAlpha(1);
onDragItemAnimationEnd();
}
});
} else {
onDragItemAnimationEnd();
}
}
});
}
private void onDragItemAnimationEnd() {
mAdapter.setDragItemId(NO_ID);
mAdapter.setDropTargetId(NO_ID);
mAdapter.notifyDataSetChanged();
mDragState = DragState.DRAG_ENDED;
if (mListener != null) {
mListener.onDragEnded(mDragItemPosition);
}
mDragItemId = NO_ID;
mDragItem.hide();
setEnabled(true);
invalidate();
}
int getDragPositionForY(float y) {
View child = findChildView(0, y);
int pos;
if (child == null && getChildCount() > 0) {
// If child is null and child count is not 0 it means that an item was
// dragged below the last item in the list, then put it after that item
pos = getChildLayoutPosition(getChildAt(getChildCount() - 1)) + 1;
} else {
pos = getChildLayoutPosition(child);
}
// If pos is NO_POSITION it means that the child has not been laid out yet,
// this only happens for pos 0 as far as I know
if (pos == NO_POSITION) {
pos = 0;
}
return pos;
}
void addDragItemAndStart(float y, Object item, long itemId) {
int pos = getDragPositionForY(y);
mDragState = DragState.DRAG_STARTED;
mDragItemId = itemId;
mAdapter.setDragItemId(mDragItemId);
mAdapter.addItem(pos, item);
mDragItemPosition = pos;
mHoldChangePosition = true;
postDelayed(new Runnable() {
@Override
public void run() {
mHoldChangePosition = false;
}
}, getItemAnimator().getMoveDuration());
invalidate();
}
Object removeDragItemAndEnd() {
if (mDragItemPosition == NO_POSITION) {
return null;
}
mAutoScroller.stopAutoScroll();
Object item = mAdapter.removeItem(mDragItemPosition);
mAdapter.setDragItemId(NO_ID);
mDragState = DragState.DRAG_ENDED;
mDragItemId = NO_ID;
invalidate();
return item;
}
}

View file

@ -1,330 +0,0 @@
/*
* Copyright 2014 Magnus Woxblom
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.woxthebox.draglistview;
import android.content.Context;
import android.graphics.drawable.Drawable;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import com.woxthebox.draglistview.swipe.ListSwipeHelper;
public class DragListView extends FrameLayout {
public interface DragListListener {
void onItemDragStarted(int position);
void onItemDragging(int itemPosition, float x, float y);
void onItemDragEnded(int fromPosition, int toPosition);
}
public static abstract class DragListListenerAdapter implements DragListListener {
@Override
public void onItemDragStarted(int position) {
}
@Override
public void onItemDragging(int itemPosition, float x, float y) {
}
@Override
public void onItemDragEnded(int fromPosition, int toPosition) {
}
}
public interface DragListCallback {
boolean canDragItemAtPosition(int dragPosition);
boolean canDropItemAtPosition(int dropPosition);
}
public static abstract class DragListCallbackAdapter implements DragListCallback {
@Override
public boolean canDragItemAtPosition(int dragPosition) {
return true;
}
@Override
public boolean canDropItemAtPosition(int dropPosition) {
return true;
}
}
private DragItemRecyclerView mRecyclerView;
private DragListListener mDragListListener;
private DragListCallback mDragListCallback;
private DragItem mDragItem;
private ListSwipeHelper mSwipeHelper;
private float mTouchX;
private float mTouchY;
public DragListView(Context context) {
super(context);
}
public DragListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mDragItem = new DragItem(getContext());
mRecyclerView = createRecyclerView();
mRecyclerView.setDragItem(mDragItem);
addView(mRecyclerView);
addView(mDragItem.getDragItemView());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean retValue = handleTouchEvent(event);
return retValue || super.onInterceptTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean retValue = handleTouchEvent(event);
return retValue || super.onTouchEvent(event);
}
private boolean handleTouchEvent(MotionEvent event) {
mTouchX = event.getX();
mTouchY = event.getY();
if (isDragging()) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mRecyclerView.onDragging(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mRecyclerView.onDragEnded();
break;
}
return true;
}
return false;
}
private DragItemRecyclerView createRecyclerView() {
final DragItemRecyclerView recyclerView = (DragItemRecyclerView) LayoutInflater.from(getContext()).inflate(R.layout.drag_item_recycler_view, this, false);
recyclerView.setMotionEventSplittingEnabled(false);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setVerticalScrollBarEnabled(false);
recyclerView.setHorizontalScrollBarEnabled(false);
recyclerView.setDragItemListener(new DragItemRecyclerView.DragItemListener() {
private int mDragStartPosition;
@Override
public void onDragStarted(int itemPosition, float x, float y) {
getParent().requestDisallowInterceptTouchEvent(true);
mDragStartPosition = itemPosition;
if (mDragListListener != null) {
mDragListListener.onItemDragStarted(itemPosition);
}
}
@Override
public void onDragging(int itemPosition, float x, float y) {
if (mDragListListener != null) {
mDragListListener.onItemDragging(itemPosition, x, y);
}
}
@Override
public void onDragEnded(int newItemPosition) {
if (mDragListListener != null) {
mDragListListener.onItemDragEnded(mDragStartPosition, newItemPosition);
}
}
});
recyclerView.setDragItemCallback(new DragItemRecyclerView.DragItemCallback() {
@Override
public boolean canDragItemAtPosition(int dragPosition) {
return mDragListCallback == null || mDragListCallback.canDragItemAtPosition(dragPosition);
}
@Override
public boolean canDropItemAtPosition(int dropPosition) {
return mDragListCallback == null || mDragListCallback.canDropItemAtPosition(dropPosition);
}
});
return recyclerView;
}
public void setSwipeListener(ListSwipeHelper.OnSwipeListener swipeListener) {
if (mSwipeHelper == null) {
mSwipeHelper = new ListSwipeHelper(getContext().getApplicationContext(), swipeListener);
} else {
mSwipeHelper.setSwipeListener(swipeListener);
}
// Always detach first so we don't get double listeners
mSwipeHelper.detachFromRecyclerView();
if (swipeListener != null) {
mSwipeHelper.attachToRecyclerView(mRecyclerView);
}
}
/**
* Resets the swipe state of all list item views except the one that is passed as an exception view.
*
* @param exceptionView This view will not be reset.
*/
public void resetSwipedViews(View exceptionView) {
if (mSwipeHelper != null) {
mSwipeHelper.resetSwipedViews(exceptionView);
}
}
public RecyclerView getRecyclerView() {
return mRecyclerView;
}
public DragItemAdapter getAdapter() {
if (mRecyclerView != null) {
return (DragItemAdapter) mRecyclerView.getAdapter();
}
return null;
}
public void setAdapter(DragItemAdapter adapter, boolean hasFixedItemSize) {
mRecyclerView.setHasFixedSize(hasFixedItemSize);
mRecyclerView.setAdapter(adapter);
adapter.setDragStartedListener(new DragItemAdapter.DragStartCallback() {
@Override
public boolean startDrag(View itemView, long itemId) {
return mRecyclerView.startDrag(itemView, itemId, mTouchX, mTouchY);
}
@Override
public boolean isDragging() {
return mRecyclerView.isDragging();
}
});
}
public void swapAdapter(DragItemAdapter adapter, boolean removeAndRecycleExisting) {
mRecyclerView.swapAdapter(adapter, removeAndRecycleExisting);
adapter.setDragStartedListener(new DragItemAdapter.DragStartCallback() {
@Override
public boolean startDrag(View itemView, long itemId) {
return mRecyclerView.startDrag(itemView, itemId, mTouchX, mTouchY);
}
@Override
public boolean isDragging() {
return mRecyclerView.isDragging();
}
});
}
public void setLayoutManager(RecyclerView.LayoutManager layout) {
mRecyclerView.setLayoutManager(layout);
}
public void setDragListListener(DragListListener listener) {
mDragListListener = listener;
}
public void setDragListCallback(DragListCallback callback) {
mDragListCallback = callback;
}
public boolean isDragEnabled() {
return mRecyclerView.isDragEnabled();
}
public void setDragEnabled(boolean enabled) {
mRecyclerView.setDragEnabled(enabled);
}
public void setCustomDragItem(DragItem dragItem) {
removeViewAt(1);
DragItem newDragItem;
if (dragItem != null) {
newDragItem = dragItem;
} else {
newDragItem = new DragItem(getContext());
}
newDragItem.setCanDragHorizontally(mDragItem.canDragHorizontally());
newDragItem.setSnapToTouch(mDragItem.isSnapToTouch());
mDragItem = newDragItem;
mRecyclerView.setDragItem(mDragItem);
addView(mDragItem.getDragItemView());
}
public boolean isDragging() {
return mRecyclerView.isDragging();
}
public void setCanDragHorizontally(boolean canDragHorizontally) {
mDragItem.setCanDragHorizontally(canDragHorizontally);
}
public void setSnapDragItemToTouch(boolean snapToTouch) {
mDragItem.setSnapToTouch(snapToTouch);
}
public void setCanNotDragAboveTopItem(boolean canNotDragAboveTop) {
mRecyclerView.setCanNotDragAboveTopItem(canNotDragAboveTop);
}
public void setCanNotDragBelowBottomItem(boolean canNotDragBelowBottom) {
mRecyclerView.setCanNotDragBelowBottomItem(canNotDragBelowBottom);
}
public void setScrollingEnabled(boolean scrollingEnabled) {
mRecyclerView.setScrollingEnabled(scrollingEnabled);
}
/**
* Set if items should not reorder automatically when dragging. If reorder is disabled, drop target
* drawables can be set with {@link #setDropTargetDrawables} which will highlight the current item that
* will be swapped when dropping. By default items will reorder automatically when dragging.
*
* @param disableReorder True if reorder of items should be disabled, false otherwise.
*/
public void setDisableReorderWhenDragging(boolean disableReorder) {
mRecyclerView.setDisableReorderWhenDragging(disableReorder);
}
/**
* If {@link #setDisableReorderWhenDragging} has been set to True then a background and/or foreground drawable
* can be provided to highlight the current item which will be swapped when dropping. These drawables
* will be drawn as decorations in the RecyclerView and will not interfere with the items own background
* and foreground drawables.
*
* @param backgroundDrawable The background drawable for the item that will be swapped.
* @param foregroundDrawable The foreground drawable for the item that will be swapped.
*/
public void setDropTargetDrawables(Drawable backgroundDrawable, Drawable foregroundDrawable) {
mRecyclerView.setDropTargetDrawables(backgroundDrawable, foregroundDrawable);
}
}

View file

@ -1,201 +0,0 @@
/*
* Copyright 2017 Magnus Woxblom
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.woxthebox.draglistview.swipe;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import androidx.recyclerview.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
public class ListSwipeHelper extends RecyclerView.OnScrollListener implements RecyclerView.OnItemTouchListener {
public static abstract class OnSwipeListenerAdapter implements OnSwipeListener {
@Override
public void onItemSwipeStarted(ListSwipeItem item) {
}
@Override
public void onItemSwipeEnded(ListSwipeItem item, ListSwipeItem.SwipeDirection swipedDirection) {
}
@Override
public void onItemSwiping(ListSwipeItem item, float swipedDistanceX) {
}
}
public interface OnSwipeListener {
void onItemSwipeStarted(ListSwipeItem item);
void onItemSwipeEnded(ListSwipeItem item, ListSwipeItem.SwipeDirection swipedDirection);
void onItemSwiping(ListSwipeItem item, float swipedDistanceX);
}
private GestureListener mGestureListener;
private GestureDetector mGestureDetector;
private ListSwipeItem mSwipeView;
private RecyclerView mRecyclerView;
private OnSwipeListener mSwipeListener;
private int mTouchSlop;
public ListSwipeHelper(Context applicationContext, OnSwipeListener listener) {
mSwipeListener = listener;
mGestureListener = new GestureListener();
mGestureDetector = new GestureDetector(applicationContext, mGestureListener);
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent event) {
handleTouch(rv, event);
return mGestureListener.isSwipeStarted();
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent event) {
handleTouch(rv, event);
}
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
resetSwipedViews(null);
}
public void resetSwipedViews(View exceptionView) {
int childCount = mRecyclerView.getChildCount();
for (int i = 0; i < childCount; i++) {
View view = mRecyclerView.getChildAt(i);
if (view instanceof ListSwipeItem && view != exceptionView) {
((ListSwipeItem) view).resetSwipe(true);
}
}
}
private void handleTouch(RecyclerView rv, MotionEvent event) {
mGestureDetector.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
View swipeView = rv.findChildViewUnder(event.getX(), event.getY());
if (swipeView instanceof ListSwipeItem &&
((ListSwipeItem) swipeView).getSupportedSwipeDirection() != ListSwipeItem.SwipeDirection.NONE) {
mSwipeView = (ListSwipeItem) swipeView;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (mSwipeView != null) {
final ListSwipeItem endingSwipeView = mSwipeView;
endingSwipeView.handleSwipeUp(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (endingSwipeView.isSwipeStarted()) {
resetSwipedViews(endingSwipeView);
}
if (mSwipeListener != null) {
mSwipeListener.onItemSwipeEnded(endingSwipeView, endingSwipeView.getSwipedDirection());
}
}
});
} else {
resetSwipedViews(null);
}
mSwipeView = null;
mRecyclerView.requestDisallowInterceptTouchEvent(false);
break;
}
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
public void detachFromRecyclerView() {
if (mRecyclerView != null) {
mRecyclerView.removeOnItemTouchListener(this);
mRecyclerView.removeOnScrollListener(this);
}
mRecyclerView = null;
}
public void attachToRecyclerView(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
mRecyclerView.addOnItemTouchListener(this);
mRecyclerView.addOnScrollListener(this);
mTouchSlop = ViewConfiguration.get(mRecyclerView.getContext()).getScaledTouchSlop();
}
public void setSwipeListener(ListSwipeHelper.OnSwipeListener listener) {
mSwipeListener = listener;
}
private class GestureListener extends GestureDetector.SimpleOnGestureListener {
private boolean mSwipeStarted;
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
if (e1 == null || e2 == null || mSwipeView == null || mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
return false;
}
final float diffX = Math.abs(e2.getX() - e1.getX());
final float diffY = Math.abs(e2.getY() - e1.getY());
if (!mSwipeStarted && diffX > mTouchSlop * 2 && diffX * 0.5f > diffY) {
mSwipeStarted = true;
mRecyclerView.requestDisallowInterceptTouchEvent(true);
mSwipeView.handleSwipeMoveStarted(mSwipeListener);
if (mSwipeListener != null) {
mSwipeListener.onItemSwipeStarted(mSwipeView);
}
}
if (mSwipeStarted) {
mSwipeView.handleSwipeMove(-distanceX, mRecyclerView.getChildViewHolder(mSwipeView));
}
return mSwipeStarted;
}
@Override
public boolean onDown(MotionEvent e) {
mSwipeStarted = false;
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (!canStartSwipe(e1, e2)) {
return false;
}
mSwipeView.setFlingSpeed(velocityX);
return true;
}
boolean isSwipeStarted() {
return mSwipeStarted;
}
private boolean canStartSwipe(MotionEvent e1, MotionEvent e2) {
return !(e1 == null || e2 == null || mSwipeView == null || mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE
|| mSwipeView.getSupportedSwipeDirection() == ListSwipeItem.SwipeDirection.NONE);
}
}
}

View file

@ -1,317 +0,0 @@
/*
* Copyright 2017 Magnus Woxblom
* <p/>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.woxthebox.draglistview.swipe;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import androidx.recyclerview.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.RelativeLayout;
import com.woxthebox.draglistview.R;
public class ListSwipeItem extends RelativeLayout {
private enum SwipeState {
IDLE, // Item is not moving
SWIPING, // Item is moving because the user is swiping with the finger
ANIMATING // Item is animating
}
public enum SwipeDirection {
LEFT, RIGHT, LEFT_AND_RIGHT, NONE
}
public enum SwipeInStyle {
APPEAR, SLIDE
}
private View mLeftView;
private View mRightView;
private View mSwipeView;
private RecyclerView.ViewHolder mViewHolder;
private SwipeState mSwipeState = SwipeState.IDLE;
private float mSwipeTranslationX;
private float mStartSwipeTranslationX;
private float mFlingSpeed;
private boolean mSwipeStarted;
private int mSwipeViewId;
private int mLeftViewId;
private int mRightViewId;
private SwipeDirection mSwipeDirection = SwipeDirection.LEFT_AND_RIGHT;
private SwipeInStyle mSwipeInStyle = SwipeInStyle.APPEAR;
// Used to report swiped distance to listener. This is will be set at the start of the swipe and reset at the end.
private ListSwipeHelper.OnSwipeListener mSwipeListener;
public ListSwipeItem(Context context) {
super(context);
}
public ListSwipeItem(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public ListSwipeItem(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ListSwipeItem);
mSwipeViewId = a.getResourceId(R.styleable.ListSwipeItem_swipeViewId, -1);
mLeftViewId = a.getResourceId(R.styleable.ListSwipeItem_leftViewId, -1);
mRightViewId = a.getResourceId(R.styleable.ListSwipeItem_rightViewId, -1);
a.recycle();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mSwipeView = findViewById(mSwipeViewId);
mLeftView = findViewById(mLeftViewId);
mRightView = findViewById(mRightViewId);
if (mLeftView != null) {
mLeftView.setVisibility(View.INVISIBLE);
}
if (mRightView != null) {
mRightView.setVisibility(View.INVISIBLE);
}
}
@Override
public void setTag(Object tag) {
super.setTag(tag);
// If view holder is recyclable then reset as this view might be used to another card
if (mViewHolder != null && mViewHolder.isRecyclable()) {
resetSwipe(false);
}
}
public void setSwipeInStyle(SwipeInStyle style) {
mSwipeInStyle = style;
}
public void setSupportedSwipeDirection(SwipeDirection swipeDirection) {
mSwipeDirection = swipeDirection;
}
public SwipeDirection getSupportedSwipeDirection() {
return mSwipeDirection;
}
void setSwipeListener(ListSwipeHelper.OnSwipeListener listener) {
mSwipeListener = listener;
}
SwipeDirection getSwipedDirection() {
if (mSwipeState != SwipeState.IDLE) {
return SwipeDirection.NONE;
}
if (mSwipeView.getTranslationX() == -getMeasuredWidth()) {
return SwipeDirection.LEFT;
} else if (mSwipeView.getTranslationX() == getMeasuredWidth()) {
return SwipeDirection.RIGHT;
}
return SwipeDirection.NONE;
}
boolean isAnimating() {
return mSwipeState == SwipeState.ANIMATING;
}
boolean isSwipeStarted() {
return mSwipeStarted;
}
void setFlingSpeed(float speed) {
mFlingSpeed = speed;
}
void swipeTranslationByX(float dx) {
setSwipeTranslationX(mSwipeTranslationX + dx);
}
void setSwipeTranslationX(float x) {
// Based on supported swipe direction reset the x position
if ((mSwipeDirection == SwipeDirection.LEFT && x > 0) || (mSwipeDirection == SwipeDirection.RIGHT && x < 0) || mSwipeDirection == SwipeDirection.NONE) {
x = 0;
}
mSwipeTranslationX = x;
mSwipeTranslationX = Math.min(mSwipeTranslationX, getMeasuredWidth());
mSwipeTranslationX = Math.max(mSwipeTranslationX, -getMeasuredWidth());
mSwipeView.setTranslationX(mSwipeTranslationX);
if (mSwipeListener != null) {
mSwipeListener.onItemSwiping(this, mSwipeTranslationX);
}
if (mSwipeTranslationX < 0) {
if (mSwipeInStyle == SwipeInStyle.SLIDE) {
mRightView.setTranslationX(getMeasuredWidth() + mSwipeTranslationX);
}
mRightView.setVisibility(View.VISIBLE);
mLeftView.setVisibility(View.INVISIBLE);
} else if (mSwipeTranslationX > 0) {
if (mSwipeInStyle == SwipeInStyle.SLIDE) {
mLeftView.setTranslationX(-getMeasuredWidth() + mSwipeTranslationX);
}
mLeftView.setVisibility(View.VISIBLE);
mRightView.setVisibility(View.INVISIBLE);
} else {
mRightView.setVisibility(View.INVISIBLE);
mLeftView.setVisibility(View.INVISIBLE);
}
}
void animateToSwipeTranslationX(float x, Animator.AnimatorListener... listeners) {
if (x == mSwipeTranslationX) {
return;
}
mSwipeState = SwipeState.ANIMATING;
ObjectAnimator animator = ObjectAnimator.ofFloat(this, "SwipeTranslationX", mSwipeTranslationX, x);
animator.setDuration(250);
animator.setInterpolator(new DecelerateInterpolator());
for (Animator.AnimatorListener listener : listeners) {
if (listener != null) {
animator.addListener(listener);
}
}
animator.start();
}
void resetSwipe(boolean animate) {
if (isAnimating() || !mSwipeStarted) {
return;
}
if (mSwipeTranslationX != 0) {
if (animate) {
animateToSwipeTranslationX(0, new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mSwipeState = SwipeState.IDLE;
mSwipeListener = null;
}
});
} else {
setSwipeTranslationX(0);
mSwipeState = SwipeState.IDLE;
mSwipeListener = null;
}
} else {
mSwipeListener = null;
}
if (mViewHolder != null && !mViewHolder.isRecyclable()) {
mViewHolder.setIsRecyclable(true);
}
mViewHolder = null;
mFlingSpeed = 0;
mStartSwipeTranslationX = 0;
mSwipeStarted = false;
}
void handleSwipeUp(Animator.AnimatorListener listener) {
if (isAnimating() || !mSwipeStarted) {
return;
}
AnimatorListenerAdapter idleListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mSwipeState = SwipeState.IDLE;
if (mSwipeTranslationX == 0) {
resetSwipe(false);
}
if (mViewHolder != null) {
mViewHolder.setIsRecyclable(true);
}
}
};
if (mFlingSpeed == 0 && Math.abs(mStartSwipeTranslationX - mSwipeTranslationX) < getMeasuredWidth() / 3) {
// Bounce back
animateToSwipeTranslationX(mStartSwipeTranslationX, idleListener, listener);
} else {
// Animate to end
float newX = getTranslateToXPosition(mStartSwipeTranslationX, mSwipeTranslationX, mFlingSpeed);
animateToSwipeTranslationX(newX, idleListener, listener);
}
mStartSwipeTranslationX = 0;
mFlingSpeed = 0;
}
private float getTranslateToXPosition(float startTranslationX, float currentTranslationX, float flingSpeed) {
if (flingSpeed == 0 && Math.abs(startTranslationX - currentTranslationX) < getMeasuredWidth() / 3) {
// Bounce back
return startTranslationX;
} else if (currentTranslationX < 0) {
// Swiping done side
if (flingSpeed > 0) {
return 0;
} else {
return -getMeasuredWidth();
}
} else if (startTranslationX == 0) {
// Swiping action side from start position
if (flingSpeed < 0) {
return 0;
} else {
return getMeasuredWidth();
}
} else {
// Swiping action side from action position
if (flingSpeed > 0) {
return getMeasuredWidth();
} else {
return 0;
}
}
}
void handleSwipeMoveStarted(ListSwipeHelper.OnSwipeListener listener) {
mStartSwipeTranslationX = mSwipeTranslationX;
mSwipeListener = listener;
}
void handleSwipeMove(float dx, RecyclerView.ViewHolder viewHolder) {
if (isAnimating()) {
return;
}
mSwipeState = SwipeState.SWIPING;
if (!mSwipeStarted) {
mSwipeStarted = true;
mViewHolder = viewHolder;
mViewHolder.setIsRecyclable(false);
}
swipeTranslationByX(dx);
}
}

View file

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

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.woxthebox.draglistview.DragItemRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drag_item_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical|horizontal" />

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ListSwipeItem">
<attr name="swipeViewId" format="integer"/>
<attr name="leftViewId" format="integer"/>
<attr name="rightViewId" format="integer"/>
</declare-styleable>
</resources>

View file

@ -1573,6 +1573,7 @@ class EditorViewModel(
}
}
@Deprecated("To be deleted")
fun onActionMenuItemClicked(id: String, action: ActionItemType) {
Timber.d("onActionMenuItemClicked, id:[$id] action:[$action]")
when (action) {
@ -1919,36 +1920,6 @@ class EditorViewModel(
dispatch(Command.OpenGallery(mediaType = MIME_IMAGE_ALL))
}
fun onAddRelationBlockClicked() {
Timber.d("onAddRelationBlockClicked, ")
val focused = blocks.first { it.id == orchestrator.stores.focus.current().id }
val content = focused.content
val replace = content is Content.Text && content.text.isEmpty()
viewModelScope.launch {
if (replace) {
orchestrator.proxies.intents.send(
Intent.CRUD.Replace(
context = context,
target = focused.id,
prototype = Prototype.Relation(key = "")
)
)
} else {
orchestrator.proxies.intents.send(
Intent.CRUD.Create(
context = context,
target = focused.id,
position = Position.BOTTOM,
prototype = Prototype.Relation(key = "")
)
)
}
}
}
fun onTogglePlaceholderClicked(target: Id) {
Timber.d("onTogglePlaceholderClicked, target:[$target]")
viewModelScope.launch {
@ -2349,35 +2320,12 @@ class EditorViewModel(
)
}
private fun onEnterActionMode() {
mode = EditorMode.Action
controlPanelInteractor.onEvent(ControlPanelMachine.Event.ReadMode.OnEnter)
viewModelScope.launch {
refresh()
}
}
private fun onExitActionMode() {
mode = EditorMode.Edit
controlPanelInteractor.onEvent(ControlPanelMachine.Event.ReadMode.OnExit)
viewModelScope.launch { refresh() }
}
fun onOpenPageNavigationButtonClicked() {
Timber.d("onOpenPageNavigationButtonClicked, ")
viewModelScope.sendEvent(
analytics = analytics,
eventName = EventsDictionary.SCREEN_NAVIGATION
)
navigation.postValue(
EventWrapper(
AppNavigation.Command.OpenPageNavigationScreen(
target = context
)
)
)
}
// ----------------- Turn Into -----------------------------------------
fun onTurnIntoBlockClicked(target: String, uiBlock: UiBlock) {

View file

@ -61,11 +61,6 @@ sealed class Command {
object ClearSearchInput : Command()
data class OpenActionBar(
val block: BlockView,
val dimensions: BlockDimensions
) : Command()
data class Browse(
val url: Url
) : Command()

View file

@ -7,7 +7,6 @@ include ':app',
':device',
':presentation',
':core-ui',
':library-kanban-widget',
':library-page-icon-picker-widget',
':library-emojifier',
':library-syntax-highlighter',