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

367 Block action bar, part 1 (#378)

* #367: add action icons

* #367: add action bar view

* #367: class Mark as Parcelable, Mark.param as String?

* #367: blockView, add parcelable

* #367: update Parcelize

* #367: block action toolbar + layout

* #367: fix name

* #367: update versions

* #367: show action bar fragment + listener

* #367: block adapter on long click

* #367: add custom long click listener

* #367: add custom long click listener to paragraph block

* #367: dismiss action bar

* #367: update page fragment on back pressed

* #367: update clicks + hide keybard

* #367: add animation

* #367: add divider

* #367: update kotlin

* #367: fix else

* #367: sample app

* #367: fix linking conflict

* #367: pr fixes

* #367: update method
This commit is contained in:
Konstantin Ivanov 2020-04-20 20:40:23 +03:00 committed by GitHub
parent 43970f3172
commit 5cb4bf9c4c
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
42 changed files with 987 additions and 47 deletions

View file

@ -29,6 +29,7 @@ import com.agileburo.anytype.core_ui.reactive.clicks
import com.agileburo.anytype.core_ui.state.ControlPanelState
import com.agileburo.anytype.core_ui.tools.FirstItemInvisibilityDetector
import com.agileburo.anytype.core_ui.tools.OutsideClickDetector
import com.agileburo.anytype.core_ui.widgets.ActionItemType
import com.agileburo.anytype.core_ui.widgets.toolbar.ActionToolbarWidget.ActionConfig.ACTION_DELETE
import com.agileburo.anytype.core_ui.widgets.toolbar.ActionToolbarWidget.ActionConfig.ACTION_DUPLICATE
import com.agileburo.anytype.core_ui.widgets.toolbar.ActionToolbarWidget.ActionConfig.ACTION_REDO
@ -62,10 +63,7 @@ import com.agileburo.anytype.ext.extractMarks
import com.agileburo.anytype.presentation.page.PageViewModel
import com.agileburo.anytype.presentation.page.PageViewModelFactory
import com.agileburo.anytype.ui.base.NavigationFragment
import com.agileburo.anytype.ui.page.modals.AddBlockFragment
import com.agileburo.anytype.ui.page.modals.CreateBookmarkFragment
import com.agileburo.anytype.ui.page.modals.PageIconPickerFragment
import com.agileburo.anytype.ui.page.modals.SetLinkFragment
import com.agileburo.anytype.ui.page.modals.*
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.hbisoft.pickit.PickiT
import com.hbisoft.pickit.PickiTCallbacks
@ -145,7 +143,8 @@ open class PageFragment :
onToggleClicked = vm::onToggleClicked,
onMediaBlockMenuClick = vm::onMediaBlockMenuClicked,
onBookmarkMenuClicked = vm::onBookmarkMenuClicked,
onMarkupActionClicked = vm::onMarkupActionClicked
onMarkupActionClicked = vm::onMarkupActionClicked,
onLongClickListener = vm::onBlockLongPressedClicked
)
}
@ -260,11 +259,12 @@ open class PageFragment :
setupOnBackPressedDispatcher()
}
private fun setupOnBackPressedDispatcher() {
private fun setupOnBackPressedDispatcher() =
requireActivity()
.onBackPressedDispatcher
.addCallback(this) { vm.onSystemBackPressed() }
}
.addCallback(this) {
vm.onSystemBackPressed(childFragmentManager.backStackEntryCount > 0)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -558,6 +558,10 @@ open class PageFragment :
vm.commands.observe(viewLifecycleOwner, Observer { execute(it) })
}
override fun onBlockActionClicked(id: String, action: ActionItemType) {
vm.onActionBarItemClicked(id, action)
}
private fun handleFocus(focus: Id) {
Timber.d("Handling focus: $focus")
if (focus.isEmpty()) {
@ -593,6 +597,17 @@ open class PageFragment :
is PageViewModel.Command.RequestDownloadPermission -> {
startDownloadWithPermissionCheck(command.id)
}
is PageViewModel.Command.PopBackStack -> {
childFragmentManager.popBackStack()
}
is PageViewModel.Command.OpenActionBar -> {
hideKeyboard()
childFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.action_bar_enter, R.anim.action_bar_exit)
.add(R.id.root, BlockActionToolbar.newInstance(command.block), null)
.addToBackStack(null)
.commit()
}
}
}
}
@ -728,9 +743,15 @@ open class PageFragment :
const val ID_EMPTY_VALUE = ""
const val NOT_IMPLEMENTED_MESSAGE = "Not implemented."
}
override fun onDismissBlockActionToolbar() {
vm.onSystemBackPressed(childFragmentManager.backStackEntryCount > 0)
}
}
interface OnFragmentInteractionListener {
fun onAddMarkupLinkClicked(blockId: String, link: String, range: IntRange)
fun onRemoveMarkupLinkClicked(blockId: String, range: IntRange)
fun onBlockActionClicked(id: String, action: ActionItemType)
fun onDismissBlockActionToolbar()
}

View file

@ -0,0 +1,232 @@
package com.agileburo.anytype.ui.page.modals
import android.content.Context
import android.os.Bundle
import android.os.Parcelable
import android.text.method.ScrollingMovementMethod
import android.view.View
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import com.agileburo.anytype.R
import com.agileburo.anytype.core_ui.extensions.color
import com.agileburo.anytype.core_ui.extensions.addVerticalDivider
import com.agileburo.anytype.core_ui.features.page.BlockView
import com.agileburo.anytype.core_ui.widgets.BlockActionBarItem
import com.agileburo.anytype.core_ui.widgets.ActionItemType
import com.agileburo.anytype.ui.page.OnFragmentInteractionListener
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.action_toolbar.*
class BlockActionToolbar : Fragment(R.layout.action_toolbar) {
companion object {
val ARG_BLOCK = "arg.block"
fun newInstance(block: BlockView): BlockActionToolbar =
BlockActionToolbar().apply {
arguments = bundleOf(ARG_BLOCK to block)
}
}
private var block: BlockView? = null
private var actionClick: (ActionItemType) -> Unit = {}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
block = arguments?.getParcelable<BlockView.Paragraph>(ARG_BLOCK)
actionClick = { actionType: ActionItemType ->
(parentFragment as? OnFragmentInteractionListener)?.onBlockActionClicked(
block?.id.orEmpty(),
actionType
)
}
container.setOnClickListener {
(parentFragment as? OnFragmentInteractionListener)?.onDismissBlockActionToolbar()
}
text.movementMethod = ScrollingMovementMethod()
text.text = (block as? BlockView.Paragraph)?.text
when (block) {
is BlockView.Paragraph -> addButtons(ACTIONS.TEXT)
is BlockView.Title -> addButtons(ACTIONS.TEXT)
is BlockView.HeaderOne -> addButtons(ACTIONS.TEXT)
is BlockView.HeaderTwo -> addButtons(ACTIONS.TEXT)
is BlockView.HeaderThree -> addButtons(ACTIONS.TEXT)
is BlockView.Highlight -> addButtons(ACTIONS.TEXT)
is BlockView.Code -> addButtons(ACTIONS.CODE)
is BlockView.Checkbox -> addButtons(ACTIONS.TEXT)
is BlockView.Task -> addButtons(ACTIONS.TEXT)
is BlockView.Bulleted -> addButtons(ACTIONS.TEXT)
is BlockView.Numbered -> addButtons(ACTIONS.TEXT)
is BlockView.Toggle -> addButtons(ACTIONS.TEXT)
is BlockView.Contact -> TODO()
is BlockView.File.View -> addButtons(ACTIONS.FILE)
is BlockView.File.Upload -> addButtons(ACTIONS.FILE)
is BlockView.File.Placeholder -> addButtons(ACTIONS.FILE)
is BlockView.File.Error -> addButtons(ACTIONS.FILE)
is BlockView.Video.View -> addButtons(ACTIONS.VIDEO_PICTURE)
is BlockView.Video.Upload -> addButtons(ACTIONS.VIDEO_PICTURE)
is BlockView.Video.Placeholder -> addButtons(ACTIONS.VIDEO_PICTURE)
is BlockView.Video.Error -> addButtons(ACTIONS.VIDEO_PICTURE)
is BlockView.Page -> addButtons(ACTIONS.PAGE)
is BlockView.Divider -> addButtons(ACTIONS.DIVIDER)
is BlockView.Bookmark.Placeholder -> addButtons(ACTIONS.BOOKMARK)
is BlockView.Bookmark.View -> addButtons(ACTIONS.BOOKMARK)
is BlockView.Bookmark.Error -> addButtons(ACTIONS.BOOKMARK)
is BlockView.Picture.View -> addButtons(ACTIONS.VIDEO_PICTURE)
is BlockView.Picture.Placeholder -> addButtons(ACTIONS.VIDEO_PICTURE)
is BlockView.Picture.Error -> addButtons(ACTIONS.VIDEO_PICTURE)
is BlockView.Picture.Upload -> addButtons(ACTIONS.VIDEO_PICTURE)
BlockView.Footer -> TODO()
}
}
private fun addButtons(actions: List<ActionItemType>) =
with(action_container) {
actions.forEach { type ->
when (type) {
ActionItemType.Divider -> {
addVerticalDivider(
height = 1,
alpha = 1.0f,
color = context.color(R.color.light_grayish)
)
}
ActionItemType.DividerExtended -> {
addVerticalDivider(
height = 8,
alpha = 1.0f,
color = context.color(R.color.light_grayish)
)
}
else -> {
addView(
createActionBarItem(
type = type,
context = requireContext(),
actionClick = actionClick
)
)
}
}
}
}
private fun createActionBarItem(
type: ActionItemType,
context: Context,
actionClick: (ActionItemType) -> Unit
) = BlockActionBarItem(context = context).apply {
setTypeAndClick(
itemType = type,
clickListener = { actionClick(it) }
)
}
object ACTIONS {
val PAGE = listOf(
ActionItemType.TurnInto,
ActionItemType.Divider,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.Rename,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.DividerExtended,
ActionItemType.Color,
ActionItemType.Divider,
ActionItemType.Background
)
val TEXT = listOf(
ActionItemType.TurnInto,
ActionItemType.Divider,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.DividerExtended,
ActionItemType.Style,
ActionItemType.Divider,
ActionItemType.Color,
ActionItemType.Divider,
ActionItemType.Background
)
val VIDEO_PICTURE = listOf(
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.Download,
ActionItemType.Divider,
ActionItemType.Replace,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.Divider,
ActionItemType.AddCaption,
ActionItemType.DividerExtended,
ActionItemType.Background
)
val FILE = listOf(
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.Download,
ActionItemType.Divider,
ActionItemType.Replace,
ActionItemType.Divider,
ActionItemType.Rename,
ActionItemType.Divider,
ActionItemType.MoveTo,
ActionItemType.DividerExtended,
ActionItemType.Color,
ActionItemType.Divider,
ActionItemType.Background
)
val BOOKMARK = listOf(
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo
)
val CODE = listOf(
ActionItemType.TurnInto,
ActionItemType.Divider,
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo
)
val DIVIDER = listOf(
ActionItemType.Delete,
ActionItemType.Divider,
ActionItemType.Duplicate,
ActionItemType.Divider,
ActionItemType.MoveTo
)
}
}
sealed class ActionType {
@Parcelize
data class Text(val id: String, val text: String) : ActionType(), Parcelable
@Parcelize
data class MediaImage(val id: String, val url: String) : ActionType(), Parcelable
}

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<scale android:fromXScale="0.9" android:toXScale="1.0"
android:fromYScale="0.9" android:toYScale="1.0"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@android:anim/accelerate_interpolator"
android:duration="220" />
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:interpolator="@android:interpolator/decelerate_cubic"
android:duration="150" />
</set>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false" >
<scale android:fromXScale="1.0" android:toXScale="0.9"
android:fromYScale="1.0" android:toYScale="0.9"
android:pivotX="50%" android:pivotY="50%"
android:interpolator="@android:interpolator/decelerate_quint"
android:duration="220" />
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
android:interpolator="@android:interpolator/decelerate_cubic"
android:duration="150"/>
</set>

View file

@ -0,0 +1,40 @@
<?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="#52000000"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/action_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginEnd="48dp"
android:layout_marginBottom="16dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_height="200dp"/>
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:padding="@dimen/dp_16"
style="@style/BlockTextContentStyle"
android:background="@drawable/rounded_text_action_bg"
app:layout_constraintBottom_toTopOf="@+id/action_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_height="200dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -75,4 +75,9 @@
<item name="android:windowSoftInputMode">adjustResize</item>
</style>
<!-- resolve linking conflicts between constrain:2.0.0-beta4 and Android Studio 3.6.3 -->
<attr name="flow_horizontalGap" format="dimension" />
<attr name="flow_horizontalSeparator" format="dimension"/>
</resources>

View file

@ -1,7 +1,7 @@
apply from: './dependencies.gradle'
buildscript {
ext.kotlin_version = '1.3.70'
ext.kotlin_version = '1.3.72'
ext.gradle_tools = '3.1.3'
ext.build_tools = '29.0.0'
ext.nav_version = '2.2.0-rc01'
@ -28,7 +28,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath 'com.android.tools.build:gradle:3.6.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
classpath 'com.google.gms:google-services:4.3.3'

View file

@ -49,7 +49,6 @@ dependencies {
implementation applicationDependencies.kotlin
implementation applicationDependencies.coroutines
implementation applicationDependencies.androidxCore
implementation applicationDependencies.ktxCore
implementation applicationDependencies.design
implementation applicationDependencies.recyclerView

View file

@ -2,6 +2,7 @@ package com.agileburo.anytype.core_ui.common
import android.graphics.Color
import android.graphics.Typeface
import android.os.Parcelable
import android.text.Annotation
import android.text.Editable
import android.text.Spannable
@ -11,6 +12,7 @@ import com.agileburo.anytype.core_utils.ext.KEY_ROUNDED
import com.agileburo.anytype.core_utils.ext.VALUE_ROUNDED
import com.agileburo.anytype.core_utils.ext.removeRoundedSpans
import com.agileburo.anytype.core_utils.ext.removeSpans
import kotlinx.android.parcel.Parcelize
/**
* Classes implementing this interface should support markup rendering.
@ -32,14 +34,15 @@ interface Markup {
* @property to caracter index where this markup ends (inclusive)
* @property type markup's type
*/
@Parcelize
data class Mark(
val from: Int,
val to: Int,
val type: Type,
val param: Any? = null
) {
val param: String? = null
) : Parcelable {
fun color(): Int = Color.parseColor(param as String)
fun color(): Int = Color.parseColor(param)
}
@ -96,7 +99,7 @@ fun Markup.toSpannable() = SpannableStringBuilder(body).apply {
Markup.DEFAULT_SPANNABLE_FLAG
)
Markup.Type.LINK -> setSpan(
URLSpan(mark.param as String),
URLSpan(mark.param),
mark.from,
mark.to,
Markup.DEFAULT_SPANNABLE_FLAG
@ -155,7 +158,7 @@ fun Editable.setMarkup(markup: Markup) {
)
Markup.Type.LINK -> {
setSpan(
URLSpan(mark.param as String),
URLSpan(mark.param),
mark.from,
mark.to,
Markup.DEFAULT_SPANNABLE_FLAG

View file

@ -3,8 +3,10 @@ package com.agileburo.anytype.core_ui.extensions
import android.content.Context
import android.content.res.ColorStateList
import android.view.View
import android.widget.LinearLayout
import android.widget.Toast
import com.agileburo.anytype.core_ui.R
import com.agileburo.anytype.core_utils.ext.px
fun View.invisible() {
this.visibility = View.INVISIBLE
@ -35,4 +37,19 @@ fun Context.toast(
fun View.tint(color: Int) {
backgroundTintList = ColorStateList.valueOf(color)
}
}
fun LinearLayout.addVerticalDivider(
alpha: Float,
height: Int,
color: Int
) = addView(
View(context).apply {
setBackgroundColor(color)
setAlpha(alpha)
layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
height
)
}
)

View file

@ -75,7 +75,8 @@ class BlockAdapter(
private val onToggleClicked: (String) -> Unit,
private val onMediaBlockMenuClick: (String) -> Unit,
private val onBookmarkMenuClicked: (String) -> Unit,
private val onMarkupActionClicked: (Markup.Type) -> Unit
private val onMarkupActionClicked: (Markup.Type) -> Unit,
private val onLongClickListener: (BlockView) -> Unit
) : RecyclerView.Adapter<BlockViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlockViewHolder {
@ -449,7 +450,8 @@ class BlockAdapter(
item = blocks[position] as BlockView.Paragraph,
onTextChanged = onParagraphTextChanged,
onSelectionChanged = onSelectionChanged,
onFocusChanged = onFocusChanged
onFocusChanged = onFocusChanged,
onLongClickListener = onLongClickListener
)
}
is BlockViewHolder.Title -> {

View file

@ -1,5 +1,6 @@
package com.agileburo.anytype.core_ui.features.page
import android.os.Parcelable
import com.agileburo.anytype.core_ui.common.Checkable
import com.agileburo.anytype.core_ui.common.Focusable
import com.agileburo.anytype.core_ui.common.Markup
@ -35,11 +36,13 @@ import com.agileburo.anytype.core_ui.features.page.BlockViewHolder.Companion.HOL
import com.agileburo.anytype.core_ui.features.page.BlockViewHolder.Companion.HOLDER_VIDEO_ERROR
import com.agileburo.anytype.core_ui.features.page.BlockViewHolder.Companion.HOLDER_VIDEO_PLACEHOLDER
import com.agileburo.anytype.core_ui.features.page.BlockViewHolder.Companion.HOLDER_VIDEO_UPLOAD
import kotlinx.android.parcel.IgnoredOnParcel
import kotlinx.android.parcel.Parcelize
/**
* UI-models for different types of blocks.
*/
sealed class BlockView : ViewType {
sealed class BlockView : ViewType, Parcelable {
/**
@ -85,6 +88,7 @@ sealed class BlockView : ViewType {
* @property focused whether this block is currently focused or not
* @property color text color
*/
@Parcelize
data class Paragraph(
override val id: String,
override val text: String,
@ -104,6 +108,7 @@ sealed class BlockView : ViewType {
* @property text text content (i.e. title text)
* @property emoji emoji as a page's logo (if present)
*/
@Parcelize
data class Title(
override val id: String,
override val focused: Boolean,
@ -119,6 +124,7 @@ sealed class BlockView : ViewType {
* @property text header's content (i.e. a header's text)
* @property color text color
*/
@Parcelize
data class HeaderOne(
override val id: String,
override val text: String,
@ -135,6 +141,7 @@ sealed class BlockView : ViewType {
* @property text header's content (i.e. a header's text)
* @property color text color
*/
@Parcelize
data class HeaderTwo(
override val id: String,
override val color: String? = null,
@ -151,6 +158,7 @@ sealed class BlockView : ViewType {
* @property text header's content (i.e. a header's text)
* @property color text color
*/
@Parcelize
data class HeaderThree(
override val id: String,
override val color: String? = null,
@ -166,6 +174,7 @@ sealed class BlockView : ViewType {
* @property id block's id
* @property text block's content
*/
@Parcelize
data class Highlight(
override val id: String,
val text: String,
@ -179,6 +188,7 @@ sealed class BlockView : ViewType {
* @property id block's id
* @property snippet blocks's content (i.e. code snippet)
*/
@Parcelize
data class Code(
override val id: String,
val snippet: String
@ -192,6 +202,7 @@ sealed class BlockView : ViewType {
* @property text checkbox's content text
* @property isChecked immutable checkbox state (whether this checkbox is checked or not)
*/
@Parcelize
data class Checkbox(
override val id: String,
override val marks: List<Markup.Mark> = emptyList(),
@ -212,6 +223,7 @@ sealed class BlockView : ViewType {
* @property text task's content text
* @property checked immutable taks state (whether this task is completed or not)
*/
@Parcelize
data class Task(
override val id: String,
val text: String,
@ -227,6 +239,7 @@ sealed class BlockView : ViewType {
* @property indent indentation value
* @property color text color
*/
@Parcelize
data class Bulleted(
override val id: String,
override val marks: List<Markup.Mark> = emptyList(),
@ -247,6 +260,7 @@ sealed class BlockView : ViewType {
* @property number number value
* @property indent indentation value
*/
@Parcelize
data class Numbered(
override val id: String,
override val text: String,
@ -268,6 +282,7 @@ sealed class BlockView : ViewType {
* @property indent indentation value
* @property toggled toggle state (whether this toggle is expanded or not)
*/
@Parcelize
data class Toggle(
override val id: String,
override val text: String,
@ -289,6 +304,7 @@ sealed class BlockView : ViewType {
* @property name a person's name
* @property avatar a person's avatar image
*/
@Parcelize
data class Contact(
override val id: String,
val name: String,
@ -303,12 +319,13 @@ sealed class BlockView : ViewType {
*/
sealed class File(
override val id: String
) : BlockView(), Indentable {
) : BlockView(), Indentable, Parcelable {
/**
* UI-model for block containing file, with state DONE.
* @property id block's id
*/
@Parcelize
data class View(
override val id: String,
override val indent: Int,
@ -325,6 +342,7 @@ sealed class BlockView : ViewType {
* UI-model for block containing file, with state UPLOADING.
* @property id block's id
*/
@Parcelize
data class Upload(
override val id: String,
override val indent: Int
@ -336,6 +354,7 @@ sealed class BlockView : ViewType {
* UI-model for block containing file, with state EMPTY.
* @property id block's id
*/
@Parcelize
data class Placeholder(
override val id: String,
override val indent: Int
@ -347,6 +366,7 @@ sealed class BlockView : ViewType {
* UI-model for block containing file, with state ERROR.
* @property id block's id
*/
@Parcelize
data class Error(
override val id: String,
override val indent: Int
@ -361,11 +381,12 @@ sealed class BlockView : ViewType {
*/
sealed class Video(
override val id: String
) : BlockView(), Indentable {
) : BlockView(), Indentable, Parcelable {
/**
* UI-model for block containing video, with state DONE.
*/
@Parcelize
data class View(
override val id: String,
override val indent: Int,
@ -382,6 +403,7 @@ sealed class BlockView : ViewType {
* UI-model for block containing video, with state UPLOADING.
* @property id block's id
*/
@Parcelize
data class Upload(
override val id: String,
override val indent: Int
@ -393,6 +415,7 @@ sealed class BlockView : ViewType {
* UI-model for block containing video, with state EMPTY.
* @property id block's id
*/
@Parcelize
data class Placeholder(
override val id: String,
override val indent: Int
@ -404,6 +427,7 @@ sealed class BlockView : ViewType {
* UI-model for block containing video, with state ERROR.
* @property id block's id
*/
@Parcelize
data class Error(
override val id: String,
override val indent: Int
@ -420,6 +444,7 @@ sealed class BlockView : ViewType {
* @property isEmpty this property determines whether this page is empty or not
* @property isArchived this property determines whether this page is archived or not
*/
@Parcelize
data class Page(
override val id: String,
override val indent: Int,
@ -435,6 +460,7 @@ sealed class BlockView : ViewType {
* UI-model for a divider block.
* @property id block's id
*/
@Parcelize
data class Divider(
override val id: String
) : BlockView() {
@ -447,11 +473,12 @@ sealed class BlockView : ViewType {
*/
sealed class Bookmark(
override val id: String
) : BlockView(), Indentable {
) : BlockView(), Indentable, Parcelable {
/**
* UI-model for a bookmark placeholder (used when bookmark url is not set)
*/
@Parcelize
data class Placeholder(
override val id: String,
override val indent: Int
@ -467,6 +494,7 @@ sealed class BlockView : ViewType {
* @property faviconUrl website's favicon url
* @property imageUrl content's main image url
*/
@Parcelize
data class View(
override val id: String,
override val indent: Int,
@ -483,6 +511,7 @@ sealed class BlockView : ViewType {
* UI-model for a bookmark view in error state
* @property url url originally entered by user to create a bookmark
*/
@Parcelize
data class Error(
override val id: String,
override val indent: Int,
@ -498,11 +527,12 @@ sealed class BlockView : ViewType {
*/
sealed class Picture(
override val id: String
) : BlockView(), Indentable {
) : BlockView(), Indentable, Parcelable {
/**
* UI-model for block containing image, with state DONE.
*/
@Parcelize
data class View(
override val id: String,
override val indent: Int,
@ -518,6 +548,7 @@ sealed class BlockView : ViewType {
/**
* UI-model for block containing image, with state EMPTY.
*/
@Parcelize
data class Placeholder(
override val id: String,
override val indent: Int
@ -528,6 +559,7 @@ sealed class BlockView : ViewType {
/**
* UI-model for block containing image, with state ERROR.
*/
@Parcelize
data class Error(
override val id: String,
override val indent: Int
@ -538,6 +570,7 @@ sealed class BlockView : ViewType {
/**
* UI-model for block containing image, with state UPLOADING.
*/
@Parcelize
data class Upload(
override val id: String,
override val indent: Int
@ -549,7 +582,9 @@ sealed class BlockView : ViewType {
/**
* Footer block. Just holds space at the end of the page.
*/
@Parcelize
object Footer : BlockView() {
@IgnoredOnParcel
override val id: String = FOOTER_ID
override fun getViewType() = HOLDER_FOOTER
}

View file

@ -33,6 +33,7 @@ import com.agileburo.anytype.core_ui.features.page.BlockViewDiffUtil.Payload
import com.agileburo.anytype.core_ui.menu.TextStyleMenu
import com.agileburo.anytype.core_ui.tools.DefaultSpannableFactory
import com.agileburo.anytype.core_ui.tools.DefaultTextWatcher
import com.agileburo.anytype.core_ui.widgets.text.EditorLongClickListener
import com.agileburo.anytype.core_ui.widgets.text.TextInputWidget
import com.agileburo.anytype.core_utils.const.MimeTypes
import com.agileburo.anytype.core_utils.ext.dimen
@ -107,10 +108,13 @@ sealed class BlockViewHolder(view: View) : RecyclerView.ViewHolder(view) {
item: BlockView.Paragraph,
onTextChanged: (String, Editable) -> Unit,
onSelectionChanged: (String, IntRange) -> Unit,
onFocusChanged: (String, Boolean) -> Unit
onFocusChanged: (String, Boolean) -> Unit,
onLongClickListener: (BlockView) -> Unit
) {
indentize(item)
content.setOnLongClickListener(EditorLongClickListener(item, onLongClickListener))
content.clearTextWatchers()
if (item.marks.isLinksPresent()) {

View file

@ -0,0 +1,99 @@
package com.agileburo.anytype.core_ui.widgets
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import com.agileburo.anytype.core_ui.R
import com.agileburo.anytype.core_ui.extensions.drawable
import kotlinx.android.synthetic.main.action_item.view.*
sealed class ActionItemType {
object TurnInto : ActionItemType()
object Delete : ActionItemType()
object Duplicate : ActionItemType()
object Rename : ActionItemType()
object MoveTo : ActionItemType()
object Color : ActionItemType()
object Background : ActionItemType()
object Style : ActionItemType()
object Download : ActionItemType()
object Replace : ActionItemType()
object AddCaption : ActionItemType()
object Divider : ActionItemType()
object DividerExtended : ActionItemType()
}
class BlockActionBarItem @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
private var itemType: ActionItemType = ActionItemType.Divider
private var click: (ActionItemType) -> Unit = {}
init {
LayoutInflater.from(context).inflate(R.layout.action_item, this)
}
private fun updateView() {
when (itemType) {
ActionItemType.TurnInto -> updateContent(
R.string.action_bar_turn_into,
R.drawable.ic_action_turn_into
)
ActionItemType.Delete -> updateContent(
R.string.action_bar_delete,
R.drawable.ic_action_delete
)
ActionItemType.Duplicate -> updateContent(
R.string.action_bar_duplicate,
R.drawable.ic_action_duplicate
)
ActionItemType.Rename -> updateContent(
R.string.action_bar_rename,
R.drawable.ic_action_rename
)
ActionItemType.MoveTo -> updateContent(
R.string.action_bar_move_to,
R.drawable.ic_action_move_to
)
ActionItemType.Color -> updateContent(
R.string.action_bar_color,
R.drawable.ic_action_color
)
ActionItemType.Background -> updateContent(
R.string.action_bar_background,
R.drawable.ic_action_background
)
ActionItemType.Style -> updateContent(
R.string.action_bar_style,
R.drawable.ic_action_style
)
ActionItemType.Download -> updateContent(
R.string.action_bar_download,
R.drawable.ic_action_download
)
ActionItemType.Replace -> updateContent(
R.string.action_bar_replace,
R.drawable.ic_action_replace
)
ActionItemType.AddCaption -> updateContent(
R.string.action_bar_add_caption,
R.drawable.ic_action_add_caption
)
else -> throw RuntimeException("Unknown action item type:$itemType")
}
}
private fun updateContent(text: Int, img: Int) {
tvAction.text = resources.getText(text)
ivAction.setImageDrawable(context.drawable(img))
}
fun setTypeAndClick(itemType: ActionItemType, clickListener: (ActionItemType) -> Unit) {
this.click = clickListener
this.itemType = itemType
setOnClickListener { click.invoke(itemType) }
updateView()
}
}

View file

@ -0,0 +1,17 @@
package com.agileburo.anytype.core_ui.widgets.text
import android.view.View
class EditorLongClickListener<T>(t: T, private val click: (T) -> Unit) :
View.OnLongClickListener {
var value: T = t
override fun onLongClick(view: View?): Boolean =
if (view != null && !view.hasFocus()) {
click(value)
true
} else {
false
}
}

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M5,3L19,3A2,2 0,0 1,21 5L21,15A2,2 0,0 1,19 17L5,17A2,2 0,0 1,3 15L3,5A2,2 0,0 1,5 3z"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ACA996"/>
<path
android:pathData="M9,22V20H17V22H9Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M3,22V20H7V22H3Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M19,22V20H21V22H19Z"
android:fillColor="#ACA996"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="23dp"
android:viewportWidth="22"
android:viewportHeight="23">
<path
android:pathData="M11,11.2695m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:fillColor="#FEF3C5"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="22dp"
android:height="22dp"
android:viewportWidth="22"
android:viewportHeight="22">
<path
android:pathData="M11,11m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:fillColor="#2C2B27"/>
</vector>

View file

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M9,8H11V18H9V8Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M4,6C3.4477,6 3,5.5523 3,5C3,4.4477 3.4477,4 4,4L20,4C20.5523,4 21,4.4477 21,5C21,5.5523 20.5523,6 20,6L4,6Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M13,8H15V18H13V8Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M5,6H7V19C7,19.5523 7.4477,20 8,20H16C16.5523,20 17,19.5523 17,19V6H19C19,8.4687 19,15.0927 19,19.0004C19,20.6572 17.6569,22 16,22H8C6.3432,22 5,20.6569 5,19V6Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M13,3H11C10.4477,3 10,3.4477 10,4H14C14,3.4477 13.5523,3 13,3ZM11,1C9.3432,1 8,2.3431 8,4V6H16V4C16,2.3431 14.6569,1 13,1H11Z"
android:fillColor="#ACA996"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M11,15.125C11,15.6082 11.4477,16 12,16C12.5523,16 13,15.6082 13,15.125V2H11V15.125Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M12,18.4L19.7071,10.7046C20.0976,10.3146 20.0976,9.6824 19.7071,9.2925C19.3166,8.9025 18.6834,8.9025 18.2929,9.2925L12,15.5759L5.7071,9.2925C5.3166,8.9025 4.6834,8.9025 4.2929,9.2925C3.9024,9.6824 3.9024,10.3146 4.2929,10.7046L12,18.4Z"
android:fillColor="#ACA996"
android:fillType="evenOdd"/>
<path
android:pathData="M4,20h16v2h-16z"
android:fillColor="#ACA996"/>
</vector>

View file

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M5,7L15,7A2,2 0,0 1,17 9L17,19A2,2 0,0 1,15 21L5,21A2,2 0,0 1,3 19L3,9A2,2 0,0 1,5 7z"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ACA996"/>
<path
android:pathData="M9,4H19C19.5523,4 20,4.4477 20,5V15C20,15.5523 19.5523,16 19,16H18V18H19C20.6569,18 22,16.6569 22,15V5C22,3.3431 20.6569,2 19,2H9C7.3432,2 6,3.3431 6,5V6H8V5C8,4.4477 8.4477,4 9,4Z"
android:fillColor="#ACA996"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M11.2929,7.2929C11.6834,6.9024 12.3166,6.9024 12.7071,7.2929L17.4142,12L12.7071,16.7071C12.3166,17.0976 11.6834,17.0976 11.2929,16.7071C10.9024,16.3166 10.9024,15.6834 11.2929,15.2929L14.5858,12L11.2929,8.7071C10.9024,8.3166 10.9024,7.6834 11.2929,7.2929Z"
android:fillColor="#ACA996"
android:fillType="evenOdd"/>
<path
android:pathData="M7,11h8v2h-8z"
android:fillColor="#ACA996"/>
<path
android:pathData="M5.125,3L19,3A2,2 0,0 1,21 5L21,19A2,2 0,0 1,19 21L5.125,21A2,2 0,0 1,3.125 19L3.125,5A2,2 0,0 1,5.125 3z"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#ACA996"/>
</vector>

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M20,0.9766h2v22h-2z"
android:fillColor="#ACA996"/>
<path
android:pathData="M10.3255,4.9978L5.6443,19.0021H8.0926L9.1894,15.5353H14.5365L15.653,19.0021H18.3559L13.7335,4.9978H10.3255ZM9.7966,13.6354L11.8728,7.1327L13.9294,13.6354H9.7966Z"
android:fillColor="#ACA996"/>
</vector>

View file

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M19,3.9686C19,3.4163 19.4477,2.9686 20,2.9686C20.5523,2.9686 21,3.4163 21,3.9686V9.9686H19V3.9686Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M15,9.9999C14.4477,9.9999 14,9.5522 14,8.9999C14,8.4476 14.4477,7.9999 15,7.9999H21V9.9999H15Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M5,19.9999C5,20.5522 4.5523,20.9999 4,20.9999C3.4477,20.9999 3,20.5522 3,19.9999V13.9999H5V19.9999Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M9,13.9686C9.5523,13.9686 10,14.4163 10,14.9686C10,15.5209 9.5523,15.9686 9,15.9686H3V13.9686H9Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M18.679,13.9686C17.8184,16.8601 15.1399,18.9686 11.9689,18.9686C8.7979,18.9686 6.1193,16.8601 5.2588,13.9686H3.1919C4.1013,17.9766 7.6857,20.9686 11.9689,20.9686C16.2521,20.9686 19.8364,17.9766 20.7459,13.9686H18.679ZM5.2588,9.9686C6.1193,7.0771 8.7979,4.9686 11.9689,4.9686C15.1399,4.9686 17.8184,7.0771 18.679,9.9686H20.7459C19.8364,5.9606 16.2521,2.9686 11.9689,2.9686C7.6857,2.9686 4.1013,5.9606 3.1919,9.9686H5.2588Z"
android:fillColor="#ACA996"
android:fillType="evenOdd"/>
</vector>

View file

@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M4.8433,5L0.1621,19.0043H2.6104L3.7073,15.5375H9.0544L10.1708,19.0043H12.8737L8.2513,5H4.8433ZM4.3144,13.6376L6.3906,7.1349L8.4472,13.6376H4.3144Z"
android:fillColor="#ACA996"/>
<path
android:pathData="M17.4811,19.2002C19.048,19.2002 19.9294,18.6322 20.6149,17.7508V19.0043H22.9457V12.2862C22.9457,9.4657 21.1438,8.5452 18.8522,8.5452C16.5605,8.5452 14.6802,9.5441 14.4648,11.9336H16.7564C16.8935,10.9151 17.4615,10.3275 18.715,10.3275C20.1253,10.3275 20.5758,10.9935 20.5758,12.3841V12.913H19.3026C16.3843,12.913 14.0535,13.7748 14.0535,16.1643C14.0535,18.2992 15.6008,19.2002 17.4811,19.2002ZM18.0491,17.4962C16.8739,17.4962 16.4038,16.9282 16.4038,16.0664C16.4038,14.8128 17.5594,14.4015 19.3614,14.4015H20.5758V15.42C20.5758,16.7519 19.5181,17.4962 18.0491,17.4962Z"
android:fillColor="#ACA996"/>
</vector>

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M8.2071,12.2929C7.8166,11.9024 7.1834,11.9024 6.7929,12.2929L2.0858,17L6.7929,21.7071C7.1834,22.0976 7.8166,22.0976 8.2071,21.7071C8.5976,21.3166 8.5976,20.6834 8.2071,20.2929L4.9142,17L8.2071,13.7071C8.5976,13.3166 8.5976,12.6834 8.2071,12.2929Z"
android:fillColor="#ACA996"
android:fillType="evenOdd"/>
<path
android:pathData="M4,16h16v2h-16z"
android:fillColor="#ACA996"/>
<path
android:pathData="M15.7926,2.2929C16.1832,1.9024 16.8163,1.9024 17.2069,2.2929L21.914,7L17.2069,11.7071C16.8163,12.0976 16.1832,12.0976 15.7926,11.7071C15.4021,11.3166 15.4021,10.6834 15.7926,10.2929L19.0855,7L15.7926,3.7071C15.4021,3.3166 15.4021,2.6834 15.7926,2.2929Z"
android:fillColor="#ACA996"
android:fillType="evenOdd"/>
<path
android:pathData="M19.9998,6l-16,0l-0,2l16,0z"
android:fillColor="#ACA996"/>
</vector>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/white" />
<solid android:color="@android:color/holo_red_dark" />
<corners
android:topLeftRadius="10dp"
android:topRightRadius="10dp" />

View file

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

View file

@ -0,0 +1,37 @@
<?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/container"
android:background="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvAction"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="11dp"
android:layout_marginBottom="9dp"
android:fontFamily="@font/graphik_font"
android:lineSpacingExtra="7sp"
android:textColor="#2C2B27"
android:textSize="17sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/ivAction"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="Turn Into" />
<ImageView
android:id="@+id/ivAction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="@+id/tvAction"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/tvAction"
tools:src="@drawable/ic_action_download" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -54,6 +54,8 @@
<color name="markup_keyboard_bg">#F3F2EC</color>
<color name="light_grayish">#f3f2ec</color>
<array name="toolbar_color_text_colors">
<item>#2C2B27</item>
<item>#ACA996</item>

View file

@ -178,5 +178,16 @@
<string-array name="certs">
<item>MIIEqDCCA5CgAwIBAgIJA071MA0GCSqGSIb3DQEBBAUAMIGUMQsww...</item>
</string-array>
<string name="action_bar_turn_into">Turn into</string>
<string name="action_bar_delete">Delete</string>
<string name="action_bar_duplicate">Duplicate</string>
<string name="action_bar_move_to">Move to</string>
<string name="action_bar_style">Style</string>
<string name="action_bar_color">Color</string>
<string name="action_bar_background">Background</string>
<string name="action_bar_download">Download</string>
<string name="action_bar_replace">Replace</string>
<string name="action_bar_add_caption">Add caption</string>
<string name="action_bar_rename">Rename</string>
</resources>

View file

@ -26,7 +26,7 @@ data class BlockEntity(
data class Mark(
val range: IntRange,
val type: Type,
val param: Any?
val param: String?
) {
enum class Type {
STRIKETHROUGH,

View file

@ -10,15 +10,14 @@ ext {
kotlin_coroutines_version = '1.3.4'
// AndroidX
androidx_core_version = '1.1.0'
androidx_core_version = '1.2.0'
androidx_test_core_version = '1.2.0'
appcompat_version = '1.1.0'
constraintLayout_version = '2.0.0-beta1'
constraintLayout_version = '2.0.0-beta4'
recyclerview_version = '1.1.0'
cardview_version = '1.0.0'
material_version = '1.1.0-beta02'
fragment_version = "1.2.3"
ktx_core_version = "1.2.0"
emoji_compat_version = '1.1.0-beta01'
view_pager_2_version = '1.0.0'
@ -98,7 +97,6 @@ ext {
design: "com.google.android.material:material:$material_version",
androidAnnotations: "androidx.annotation:annotation:$appcompat_version",
betterLinkMovement: "me.saket:better-link-movement-method:$better_link_method_version",
ktxCore: "androidx.core:core-ktx:$ktx_core_version",
emojiCompat: "androidx.emoji:emoji-appcompat:$emoji_compat_version",
glide: "com.github.bumptech.glide:glide:$glide_version",

View file

@ -103,7 +103,7 @@ data class Block(
data class Mark(
val range: IntRange,
val type: Type,
val param: Any? = null
val param: String? = null
) {
enum class Type {
STRIKETHROUGH,

View file

@ -1,7 +1,6 @@
#Tue Oct 22 17:14:40 MSK 2019
#Wed Oct 23 20:41:38 MSK 2019
#Mon Apr 13 21:05:02 MSK 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip

View file

@ -55,7 +55,7 @@ fun BlockEntity.Content.Text.Mark.toMiddleware(): Block.Content.Text.Mark {
.newBuilder()
.setType(Block.Content.Text.Mark.Type.TextColor)
.setRange(rangeModel)
.setParam(param as String)
.setParam(param)
.build()
}
BlockEntity.Content.Text.Mark.Type.LINK -> {
@ -63,7 +63,7 @@ fun BlockEntity.Content.Text.Mark.toMiddleware(): Block.Content.Text.Mark {
.newBuilder()
.setType(Block.Content.Text.Mark.Type.Link)
.setRange(rangeModel)
.setParam(param as String)
.setParam(param)
.build()
}
BlockEntity.Content.Text.Mark.Type.BACKGROUND_COLOR -> {
@ -71,7 +71,7 @@ fun BlockEntity.Content.Text.Mark.toMiddleware(): Block.Content.Text.Mark {
.newBuilder()
.setType(Block.Content.Text.Mark.Type.BackgroundColor)
.setRange(rangeModel)
.setParam(param as String)
.setParam(param)
.build()
}
BlockEntity.Content.Text.Mark.Type.KEYBOARD -> {

View file

@ -8,6 +8,7 @@ import com.agileburo.anytype.core_ui.features.page.BlockView
import com.agileburo.anytype.core_ui.features.page.pattern.Matcher
import com.agileburo.anytype.core_ui.features.page.pattern.Pattern
import com.agileburo.anytype.core_ui.state.ControlPanelState
import com.agileburo.anytype.core_ui.widgets.ActionItemType
import com.agileburo.anytype.core_utils.common.EventWrapper
import com.agileburo.anytype.core_utils.ext.*
import com.agileburo.anytype.core_utils.tools.Counter
@ -521,8 +522,12 @@ class PageViewModel(
}
}
fun onSystemBackPressed() {
proceedWithExiting()
fun onSystemBackPressed(editorHasChildrenScreens: Boolean) {
if (editorHasChildrenScreens) {
dispatch(Command.PopBackStack)
} else {
proceedWithExiting()
}
}
fun onBackButtonPressed() {
@ -755,6 +760,10 @@ class PageViewModel(
}
}
fun onBlockLongPressedClicked(block: BlockView) {
dispatch(Command.OpenActionBar(block = block))
}
fun onMarkupActionClicked(markup: Markup.Type) {
viewModelScope.launch {
markupActionChannel.send(MarkupAction(type = markup))
@ -840,6 +849,49 @@ class PageViewModel(
}
}
fun onActionBarItemClicked(id: String, action: ActionItemType) {
when (action) {
ActionItemType.TurnInto -> {
stateData.value = ViewState.Error("Turn Into not implemented")
}
ActionItemType.Delete -> {
proceedWithUnlinking(target = id)
dispatch(Command.PopBackStack)
}
ActionItemType.Duplicate -> {
duplicateBlock(target = id)
dispatch(Command.PopBackStack)
}
ActionItemType.Rename -> {
stateData.value = ViewState.Error("Rename not implemented")
}
ActionItemType.MoveTo -> {
stateData.value = ViewState.Error("Move To not implemented")
}
ActionItemType.Color -> {
stateData.value = ViewState.Error("Color not implemented")
}
ActionItemType.Background -> {
stateData.value = ViewState.Error("Background not implemented")
}
ActionItemType.Style -> {
stateData.value = ViewState.Error("Style not implemented")
}
ActionItemType.Download -> {
stateData.value = ViewState.Error("Download not implemented")
}
ActionItemType.Replace -> {
stateData.value = ViewState.Error("Replace not implemented")
}
ActionItemType.AddCaption -> {
stateData.value = ViewState.Error("Add caption not implemented")
}
ActionItemType.Divider -> {
stateData.value = ViewState.Error("not implemented")
}
}
}
private fun proceedWithUnlinking(target: String) {
// TODO support nested blocks
@ -876,11 +928,15 @@ class PageViewModel(
}
fun onActionDuplicateClicked() {
duplicateBlock(target = focusChannel.value)
}
private fun duplicateBlock(target : String) {
duplicateBlock.invoke(
scope = viewModelScope,
params = DuplicateBlock.Params(
context = context,
original = focusChannel.value
original = target
),
onResult = { result ->
result.either(
@ -1324,6 +1380,12 @@ class PageViewModel(
data class RequestDownloadPermission(
val id: String
) : Command()
object PopBackStack : Command()
data class OpenActionBar(
val block: BlockView
) : Command()
}
companion object {
@ -1334,7 +1396,7 @@ class PageViewModel(
data class MarkupAction(
val type: Markup.Type,
val param: Any? = null
val param: String? = null
)
override fun onCleared() {

View file

@ -55,8 +55,8 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation applicationDependencies.fragment
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.0.2'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation applicationDependencies.design
@ -64,6 +64,6 @@ dependencies {
kapt applicationDependencies.permissionDispCompiler
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

View file

@ -1,8 +1,14 @@
package com.agileburo.anytype.sample
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.agileburo.anytype.core_ui.widgets.BlockActionBarItem
import com.agileburo.anytype.core_ui.widgets.ActionItemType
import com.agileburo.anytype.core_ui.widgets.dialog.AboveDialog
import kotlinx.android.synthetic.main.above_fragment.*
import kotlinx.android.synthetic.main.activity_keyboard.*
import timber.log.Timber
class KeyboardActivity : AppCompatActivity(), UpdateValues {
@ -15,7 +21,38 @@ class KeyboardActivity : AppCompatActivity(), UpdateValues {
tvThree.text = "333"
btnTest.setOnClickListener {
AboveDialogFragment().show(supportFragmentManager, null)
AboveDialogFragment().apply {
//setStyle(DialogFragment.STYLE_NORMAL, R.style.AppBottomSheetDialogTheme)
}
.show(supportFragmentManager, null)
}
edtTest.setOnFocusChangeListener { v, hasFocus ->
Timber.d("EditText1 hasFocus:$hasFocus")
}
edtTest.setOnClickListener {
Timber.d("EditText1 : OnClick, hasFocus:${it.hasFocus()}")
}
edtTest.setOnLongClickListener {
Timber.d("EditText1 : OnLongClick, hasFocus: ${it.hasFocus()} , hasOtherBlocksInFocus : ${it.hasWindowFocus()}")
val focus = it.hasFocus()
if (!focus) {
TestDialog().show(supportFragmentManager, "TAG")
}
return@setOnLongClickListener !it.hasFocus()
}
with(edtTest2) {
setOnLongClickListener {
Timber.d("EditText2 : OnLongClick, hasFocus: ${it.hasFocus()}, hasOtherBlocksInFocus : ${it.hasWindowFocus()}")
val focus = it.hasFocus()
if (!focus) {
TestDialog().show(supportFragmentManager, "TAG")
}
return@setOnLongClickListener !it.hasFocus()
}
}
}
@ -39,4 +76,41 @@ interface UpdateValues {
fun update1()
fun update2()
fun update3()
}
class TestDialog : AboveDialog() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(action_container) {
addView(BlockActionBarItem(context = requireContext()).apply {
setTypeAndClick(
ActionItemType.Replace,
{})
})
addView(BlockActionBarItem(context = requireContext()).apply {
setTypeAndClick(
ActionItemType.TurnInto,
{})
})
addView(BlockActionBarItem(context = requireContext()).apply {
setTypeAndClick(
ActionItemType.Delete,
{})
})
}
}
override fun layout(): Int {
return R.layout.above_fragment
}
override fun title(): String? {
return null
}
}

View file

@ -0,0 +1,39 @@
<?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:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="32dp"
android:background="@color/chapter_yellow"
android:padding="16dp"
android:text="To generate a method trace of your app's execution, you can instrument your app using the Debug class. Instrumenting your app this way gives you more control over exactly when the device starts and stops recording tracing information. The device also saves your trace logs using the names you specify, so you can easily identify each log later. You can then view each trace log using the Android Studio CPU Profiler."
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/action_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<LinearLayout
android:id="@+id/action_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="48dp"
android:layout_marginEnd="48dp"
android:layout_marginBottom="16dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:layout_height="300dp">
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -56,8 +56,15 @@
android:id="@+id/edtTest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Test1983"
android:hint="Start typing" />
<EditText
android:id="@+id/edtTest2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Second "/>
<Button
android:id="@+id/btnTest"
android:layout_width="wrap_content"

View file

@ -6,6 +6,35 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<!-- <item name="android:dialogTheme">@style/AppBottomSheetDialogTheme</item>-->
<item name="alertDialogTheme">@style/DialogTheme</item>
<!-- <item name="android:alertDialogTheme">?alertDialogTheme</item>-->
<!-- <item name="dialogTheme">?alertDialogTheme</item>-->
</style>
<!-- define your dialog theme -->
<style name="DialogTheme" parent="Theme.AppCompat.Light.Dialog.MinWidth">
<item name="android:colorBackground">@android:color/transparent</item>
<item name="android:textColorHint">@color/colorAccent</item>
</style>
<style name="AppBottomSheetDialogTheme" parent="Theme.AppCompat.Light.Dialog">
<item name="android:colorBackground">@color/black</item>
<!-- <item name="colorPrimary">@color/black</item>-->
<!-- <item name="bottomSheetStyle">@style/AppModalStyle</item>-->
<!-- <item name="android:windowIsTranslucent">true</item>-->
<!-- <item name="android:windowBackground">@android:color/transparent</item>-->
<!-- <item name="android:windowCloseOnTouchOutside">false</item>-->
</style>
<style name="AppModalStyle" parent="Widget.Design.BottomSheet.Modal">
<item name="android:background">@drawable/rounded_dialog</item>
<item name="android:windowBackground">@color/black</item>
<item name="android:windowBackgroundFallback">@color/black</item>
<item name="android:windowFullscreen">true</item>
</style>
<attr name="flow_horizontalGap" format="dimension" />
<attr name="flow_horizontalSeparator" format="dimension"/>
</resources>