mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
Editor | Styling toolbar | Selected states (#1461)
This commit is contained in:
parent
bfa6205656
commit
df705afe6c
19 changed files with 158 additions and 105 deletions
|
@ -1125,6 +1125,7 @@ open class PageFragment :
|
|||
lifecycleScope.launch {
|
||||
hideSoftInput()
|
||||
delay(DEFAULT_ANIM_DURATION)
|
||||
stylingToolbar.setSelectedStyle(style)
|
||||
BottomSheetBehavior.from(stylingToolbar).apply {
|
||||
setState(BottomSheetBehavior.STATE_EXPANDED)
|
||||
addBottomSheetCallback(onHideBottomSheetCallback)
|
||||
|
@ -1140,6 +1141,7 @@ open class PageFragment :
|
|||
|
||||
state.styleExtraToolbar.apply {
|
||||
if (isVisible) {
|
||||
styleToolbarOther.setProperties(state.stylingToolbar.props)
|
||||
lifecycleScope.launch {
|
||||
BottomSheetBehavior.from(styleToolbarOther).apply {
|
||||
setState(BottomSheetBehavior.STATE_EXPANDED)
|
||||
|
@ -1156,6 +1158,12 @@ open class PageFragment :
|
|||
|
||||
state.styleColorToolbar.apply {
|
||||
if (isVisible) {
|
||||
state.stylingToolbar.config?.let { config ->
|
||||
styleToolbarColors.update(
|
||||
config,
|
||||
state.stylingToolbar.props
|
||||
)
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
BottomSheetBehavior.from(styleToolbarColors).apply {
|
||||
setState(BottomSheetBehavior.STATE_EXPANDED)
|
||||
|
|
|
@ -199,7 +199,7 @@
|
|||
|
||||
</FrameLayout>
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.StyleToolbarWidgetNew
|
||||
<com.anytypeio.anytype.core_ui.widgets.StyleToolbarMainWidget
|
||||
android:id="@+id/stylingToolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -210,7 +210,7 @@
|
|||
app:cardUseCompatPadding="true"
|
||||
app:layout_behavior="@string/bottom_sheet_behavior" />
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.toolbar.StyleToolbarOther
|
||||
<com.anytypeio.anytype.core_ui.widgets.toolbar.StyleToolbarExtraWidget
|
||||
android:id="@+id/styleToolbarOther"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -6,6 +6,7 @@ typealias Hash = String
|
|||
|
||||
typealias Document = List<Block>
|
||||
|
||||
typealias TextStyle = Block.Content.Text.Style
|
||||
typealias CBTextStyle = Block.Content.Text.Style
|
||||
|
||||
typealias DV = Block.Content.DataView
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.cardview.widget.CardView
|
||||
import com.anytypeio.anytype.core_models.TextStyle
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.extensions.toast
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.presentation.page.editor.model.UiBlock
|
||||
import kotlinx.android.synthetic.main.widget_style_toolbar_main.view.*
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
class StyleToolbarMainWidget @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : CardView(context, attrs) {
|
||||
|
||||
init {
|
||||
LayoutInflater
|
||||
.from(context)
|
||||
.inflate(R.layout.widget_style_toolbar_main, this)
|
||||
|
||||
callout.setOnClickListener {
|
||||
context.toast(
|
||||
msg = "Will be implemented later",
|
||||
duration = Toast.LENGTH_SHORT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val styles = merge(
|
||||
tvStyleTitle.clicks().map { UiBlock.HEADER_ONE },
|
||||
tvStyleHeading.clicks().map { UiBlock.HEADER_TWO },
|
||||
tvStyleSubheading.clicks().map { UiBlock.HEADER_THREE },
|
||||
tvStyleText.clicks().map { UiBlock.TEXT },
|
||||
checkbox.clicks().map { UiBlock.CHECKBOX },
|
||||
bulleted.clicks().map { UiBlock.BULLETED },
|
||||
numbered.clicks().map { UiBlock.NUMBERED },
|
||||
toggle.clicks().map { UiBlock.TOGGLE },
|
||||
highlight.clicks().map { UiBlock.HIGHLIGHTED },
|
||||
)
|
||||
|
||||
val other = dots.clicks()
|
||||
val colors = markupColors.clicks()
|
||||
|
||||
fun setSelectedStyle(style: TextStyle) {
|
||||
when (style) {
|
||||
TextStyle.P -> select(tvStyleText.id)
|
||||
TextStyle.H1 -> select(tvStyleTitle.id)
|
||||
TextStyle.H2 -> select(tvStyleHeading.id)
|
||||
TextStyle.H3 -> select(tvStyleSubheading.id)
|
||||
TextStyle.H4 -> select(tvStyleSubheading.id)
|
||||
TextStyle.QUOTE -> select(highlight.id)
|
||||
TextStyle.BULLET -> select(bulleted.id)
|
||||
TextStyle.NUMBERED -> select(numbered.id)
|
||||
TextStyle.TOGGLE -> select(toggle.id)
|
||||
TextStyle.CHECKBOX -> select(checkbox.id)
|
||||
else -> select(View.NO_ID)
|
||||
}
|
||||
}
|
||||
|
||||
private fun select(selectedViewId: Int) {
|
||||
tvStyleText.apply { isSelected = id == selectedViewId }
|
||||
tvStyleTitle.apply { isSelected = id == selectedViewId }
|
||||
tvStyleHeading.apply { isSelected = id == selectedViewId }
|
||||
tvStyleSubheading.apply { isSelected = id == selectedViewId }
|
||||
checkbox.apply { isSelected = id == selectedViewId }
|
||||
bulleted.apply { isSelected = id == selectedViewId }
|
||||
numbered.apply { isSelected = id == selectedViewId }
|
||||
toggle.apply { isSelected = id == selectedViewId }
|
||||
highlight.apply { isSelected = id == selectedViewId }
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package com.anytypeio.anytype.core_ui.widgets
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import androidx.cardview.widget.CardView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.presentation.page.editor.model.UiBlock
|
||||
import kotlinx.android.synthetic.main.widget_styling_toolbar_main.view.*
|
||||
import kotlinx.coroutines.flow.flattenMerge
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class StyleToolbarWidgetNew @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : CardView(context, attrs) {
|
||||
|
||||
init {
|
||||
LayoutInflater
|
||||
.from(context)
|
||||
.inflate(R.layout.widget_styling_toolbar_main, this)
|
||||
}
|
||||
|
||||
val styles = flowOf(
|
||||
tvStyleTitle.clicks().map { UiBlock.HEADER_ONE },
|
||||
tvStyleHeading.clicks().map { UiBlock.HEADER_TWO },
|
||||
tvStyleSubheading.clicks().map { UiBlock.HEADER_THREE },
|
||||
tvStyleText.clicks().map { UiBlock.TEXT },
|
||||
checkbox.clicks().map { UiBlock.CHECKBOX },
|
||||
bulleted.clicks().map { UiBlock.BULLETED },
|
||||
numbered.clicks().map { UiBlock.NUMBERED },
|
||||
toggle.clicks().map { UiBlock.TOGGLE },
|
||||
highlight.clicks().map { UiBlock.HIGHLIGHTED },
|
||||
).flattenMerge()
|
||||
|
||||
val other = dots.clicks()
|
||||
val colors = markupColors.clicks()
|
||||
|
||||
}
|
|
@ -6,13 +6,15 @@ import android.view.LayoutInflater
|
|||
import androidx.cardview.widget.CardView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.presentation.page.editor.control.ControlPanelState
|
||||
import com.anytypeio.anytype.presentation.page.editor.model.Alignment
|
||||
import com.anytypeio.anytype.presentation.page.editor.styling.StylingEvent
|
||||
import kotlinx.android.synthetic.main.widget_block_style_other.view.*
|
||||
import kotlinx.android.synthetic.main.widget_block_style_extra.view.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.merge
|
||||
|
||||
class StyleToolbarOther @JvmOverloads constructor(
|
||||
class StyleToolbarExtraWidget @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : CardView(context, attrs) {
|
||||
|
@ -20,7 +22,7 @@ class StyleToolbarOther @JvmOverloads constructor(
|
|||
init {
|
||||
LayoutInflater
|
||||
.from(context)
|
||||
.inflate(R.layout.widget_block_style_other, this)
|
||||
.inflate(R.layout.widget_block_style_extra, this)
|
||||
}
|
||||
|
||||
val actions : Flow<StylingEvent> = merge(
|
||||
|
@ -33,4 +35,15 @@ class StyleToolbarOther @JvmOverloads constructor(
|
|||
alignmentRight.clicks().map { StylingEvent.Alignment.Right },
|
||||
setUrl.clicks().map { StylingEvent.Markup.Link }
|
||||
)
|
||||
|
||||
fun setProperties(props: ControlPanelState.Toolbar.Styling.Props?) {
|
||||
bold.isSelected = props?.isBold ?: false
|
||||
italic.isSelected = props?.isItalic ?: false
|
||||
strikethrough.isSelected = props?.isStrikethrough ?: false
|
||||
code.isSelected = props?.isCode ?: false
|
||||
alignmentLeft.isSelected = props?.alignment == Alignment.START
|
||||
alignmentMiddle.isSelected = props?.alignment == Alignment.CENTER
|
||||
alignmentRight.isSelected = props?.alignment == Alignment.END
|
||||
setUrl.isSelected = props?.isLinked ?: false
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@ import android.view.LayoutInflater
|
|||
import android.widget.TextView
|
||||
import androidx.cardview.widget.CardView
|
||||
import com.anytypeio.anytype.core_ui.R
|
||||
import com.anytypeio.anytype.core_ui.reactive.clicks
|
||||
import com.anytypeio.anytype.presentation.page.editor.control.ControlPanelState
|
||||
import com.anytypeio.anytype.presentation.page.editor.styling.StyleConfig
|
||||
import com.anytypeio.anytype.presentation.page.editor.styling.StylingEvent
|
||||
|
@ -58,6 +57,4 @@ class StyleColorToolbarWidget @JvmOverloads constructor(
|
|||
blockStyleAdapter.updateConfig(config, props)
|
||||
blockStyleAdapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun closeButtonClicks() = close.clicks()
|
||||
}
|
|
@ -3,5 +3,5 @@
|
|||
<corners
|
||||
android:bottomLeftRadius="10dp"
|
||||
android:topLeftRadius="10dp" />
|
||||
<solid android:color="#FFB522" />
|
||||
<solid android:color="#1A867D42" />
|
||||
</shape>
|
|
@ -1,4 +1,4 @@
|
|||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#FFB522" />
|
||||
<solid android:color="#1A867D42" />
|
||||
</shape>
|
|
@ -3,5 +3,5 @@
|
|||
<corners
|
||||
android:bottomRightRadius="10dp"
|
||||
android:topRightRadius="10dp" />
|
||||
<solid android:color="#FFB522" />
|
||||
<solid android:color="#1A867D42" />
|
||||
</shape>
|
|
@ -109,7 +109,7 @@
|
|||
|
||||
<color name="context_menu_selected_item">#ACA996</color>
|
||||
|
||||
<color name="default_style_color_circle_outer_stroke_color">#FFB522</color>
|
||||
<color name="default_style_color_circle_outer_stroke_color">#E4E2D7</color>
|
||||
<color name="default_style_color_circle_inner_stroke_color">#DFDDD0</color>
|
||||
<color name="viewer_filter_add_stroke_color">#DFDDD0</color>
|
||||
<color name="default_tag_text_color">#E89D00</color>
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
<dimen name="popup_context_menu_height">44dp</dimen>
|
||||
<dimen name="popup_context_menu_margin">8dp</dimen>
|
||||
<dimen name="popup_context_menu_bottom_allowance">40dp</dimen>
|
||||
<dimen name="default_style_color_circle_inner_radius">24dp</dimen>
|
||||
<dimen name="default_style_color_circle_inner_radius">22dp</dimen>
|
||||
<dimen name="default_style_color_outer_stroke_width">2dp</dimen>
|
||||
|
||||
<dimen name="default_page_links_bottom_offset">64dp</dimen>
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
## For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
#
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx1536m
|
||||
# Default value: -Xmx1024m -XX:MaxPermSize=256m
|
||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||
#
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app's APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
org.gradle.jvmargs=-Xmx2048M
|
||||
|
||||
android.enableR8=true
|
||||
# Automatically convert third-party libraries to use AndroidX
|
||||
android.enableUnitTestBinaryResources=true
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=false
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
android.enableUnitTestBinaryResources=true
|
||||
|
||||
kotlin.code.style=official
|
|
@ -1,6 +1,7 @@
|
|||
package com.anytypeio.anytype.presentation.page
|
||||
|
||||
import com.anytypeio.anytype.core_models.Block
|
||||
import com.anytypeio.anytype.core_models.TextStyle
|
||||
import com.anytypeio.anytype.core_models.ext.overlap
|
||||
import com.anytypeio.anytype.core_models.misc.Overlap
|
||||
import com.anytypeio.anytype.presentation.common.StateReducer
|
||||
|
@ -416,6 +417,11 @@ sealed class ControlPanelMachine {
|
|||
}
|
||||
is Event.OnBlockActionToolbarStyleClicked -> {
|
||||
val target = target(event.target)
|
||||
val style = event.target.let {
|
||||
val content = it.content
|
||||
check(content is Block.Content.Text)
|
||||
content.style
|
||||
}
|
||||
state.copy(
|
||||
mainToolbar = state.mainToolbar.copy(
|
||||
isVisible = false
|
||||
|
@ -424,6 +430,7 @@ sealed class ControlPanelMachine {
|
|||
isVisible = true,
|
||||
mode = getModeForSelection(event.selection),
|
||||
target = target,
|
||||
style = style,
|
||||
config = event.target.getStyleConfig(event.focused, event.selection),
|
||||
props = getPropsForSelection(target, event.selection)
|
||||
),
|
||||
|
@ -521,41 +528,30 @@ sealed class ControlPanelMachine {
|
|||
state: ControlPanelState,
|
||||
event: Event.OnRefresh.StyleToolbar
|
||||
): ControlPanelState {
|
||||
return if (state.stylingToolbar.mode == StylingMode.MARKUP) {
|
||||
if (event.target != null) {
|
||||
val target = target(event.target)
|
||||
event.selection?.let {
|
||||
val props = getMarkupLevelStylingProps(target, it)
|
||||
state.copy(
|
||||
stylingToolbar = state.stylingToolbar.copy(
|
||||
props = props,
|
||||
target = target
|
||||
)
|
||||
val target = event.target?.let { target(it) }
|
||||
val style = event.target?.let {
|
||||
val content = it.content
|
||||
check(content is Block.Content.Text)
|
||||
content.style
|
||||
} ?: TextStyle.P
|
||||
return state.copy(
|
||||
stylingToolbar = state.stylingToolbar.copy(
|
||||
target = target,
|
||||
props = target?.let {
|
||||
Toolbar.Styling.Props(
|
||||
isBold = it.isBold,
|
||||
isItalic = it.isItalic,
|
||||
isStrikethrough = it.isStrikethrough,
|
||||
isCode = it.isCode,
|
||||
isLinked = it.isLinked,
|
||||
color = it.color,
|
||||
background = it.background,
|
||||
alignment = it.alignment
|
||||
)
|
||||
} ?: state.copy()
|
||||
} else {
|
||||
state.copy()
|
||||
}
|
||||
} else {
|
||||
val target = event.target?.let { target(it) }
|
||||
state.copy(
|
||||
stylingToolbar = state.stylingToolbar.copy(
|
||||
target = target,
|
||||
props = target?.let {
|
||||
Toolbar.Styling.Props(
|
||||
isBold = it.isBold,
|
||||
isItalic = it.isItalic,
|
||||
isStrikethrough = it.isStrikethrough,
|
||||
isCode = it.isCode,
|
||||
isLinked = it.isLinked,
|
||||
color = it.color,
|
||||
background = it.background,
|
||||
alignment = it.alignment
|
||||
)
|
||||
}
|
||||
)
|
||||
},
|
||||
style = style
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun getModeForSelection(selection: IntRange?): StylingMode {
|
||||
|
|
|
@ -462,7 +462,7 @@ class PageViewModel(
|
|||
|
||||
private fun refreshStyleToolbar(document: Document) {
|
||||
controlPanelViewState.value?.let { state ->
|
||||
if (state.stylingToolbar.isVisible) {
|
||||
if (state.stylingToolbar.isVisible || state.styleColorToolbar.isVisible || state.styleExtraToolbar.isVisible) {
|
||||
state.stylingToolbar.target?.id?.let { targetId ->
|
||||
controlPanelInteractor.onEvent(
|
||||
event = ControlPanelMachine.Event.OnRefresh.StyleToolbar(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.anytypeio.anytype.presentation.page.editor.control
|
||||
|
||||
import com.anytypeio.anytype.core_models.TextStyle
|
||||
import com.anytypeio.anytype.presentation.page.editor.Markup
|
||||
import com.anytypeio.anytype.presentation.page.editor.mention.Mention
|
||||
import com.anytypeio.anytype.presentation.page.editor.model.Alignment
|
||||
|
@ -104,7 +105,8 @@ data class ControlPanelState(
|
|||
val target: Target? = null,
|
||||
val config: StyleConfig? = null,
|
||||
val props: Props? = null,
|
||||
val mode: StylingMode? = null
|
||||
val mode: StylingMode? = null,
|
||||
val style: TextStyle = TextStyle.P
|
||||
) : Toolbar() {
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
android:layout_height="match_parent"
|
||||
tools:context=".StyleToolbarActivity">
|
||||
|
||||
<com.anytypeio.anytype.core_ui.widgets.StyleToolbarWidgetNew
|
||||
<com.anytypeio.anytype.core_ui.widgets.StyleToolbarMainWidget
|
||||
app:cardBackgroundColor="@color/white"
|
||||
app:cardCornerRadius="16dp"
|
||||
android:id="@+id/toolbar"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue