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:
parent
1ea7ad50e5
commit
3a256df698
68 changed files with 2 additions and 7180 deletions
2
.github/workflows/check.yml
vendored
2
.github/workflows/check.yml
vendored
|
@ -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:
|
||||
|
|
|
@ -165,7 +165,6 @@ dependencies {
|
|||
implementation analyticsDependencies.amplitude
|
||||
implementation analyticsDependencies.okhttp
|
||||
|
||||
implementation applicationDependencies.blurry
|
||||
implementation applicationDependencies.shimmerLayout
|
||||
implementation applicationDependencies.photoView
|
||||
implementation applicationDependencies.zxing
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
|
@ -74,7 +74,6 @@ interface EditorSubComponent {
|
|||
fun inject(fragment: EditorFragment)
|
||||
|
||||
fun objectIconPickerComponent(): ObjectIconPickerComponent.Builder
|
||||
fun documentActionMenuComponentBuilder(): DocumentActionMenuSubComponent.Builder
|
||||
|
||||
// Relations
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
}
|
|
@ -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)
|
||||
)
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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",
|
||||
|
|
1
library-kanban-widget/.gitignore
vendored
1
library-kanban-widget/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/build
|
|
@ -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
|
||||
}
|
|
@ -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=
|
|
@ -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
|
||||
}
|
||||
}
|
17
library-kanban-widget/proguard-rules.pro
vendored
17
library-kanban-widget/proguard-rules.pro
vendored
|
@ -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 *;
|
||||
#}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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" />
|
||||
|
|
@ -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>
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -7,7 +7,6 @@ include ':app',
|
|||
':device',
|
||||
':presentation',
|
||||
':core-ui',
|
||||
':library-kanban-widget',
|
||||
':library-page-icon-picker-widget',
|
||||
':library-emojifier',
|
||||
':library-syntax-highlighter',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue