diff --git a/analytics/build.gradle b/analytics/build.gradle index ae917c65cb..ff8df3cee1 100644 --- a/analytics/build.gradle +++ b/analytics/build.gradle @@ -29,7 +29,7 @@ dependencies { def app = rootProject.ext.mainApplication def analytics = rootProject.ext.analytics implementation app.kotlin - implementation app.coroutines + implementation app.coroutinesAndroid implementation app.timber implementation analytics.amplitude } diff --git a/app/build.gradle b/app/build.gradle index 486fcf8d2c..69d2834e49 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -106,7 +106,7 @@ dependencies { //Application dependencies implementation applicationDependencies.kotlin - implementation applicationDependencies.coroutines + implementation applicationDependencies.coroutinesAndroid implementation applicationDependencies.fragment implementation applicationDependencies.navigation implementation applicationDependencies.navigationUi @@ -118,7 +118,6 @@ dependencies { implementation applicationDependencies.dagger implementation applicationDependencies.timber implementation applicationDependencies.gson - implementation applicationDependencies.rxRelay implementation applicationDependencies.tableView implementation applicationDependencies.permissionDisp implementation applicationDependencies.pickT diff --git a/app/src/main/java/com/anytypeio/anytype/ui/database/kanban/KanbanBoardFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/database/kanban/KanbanBoardFragment.kt index a10091c62f..b25367ccf3 100755 --- a/app/src/main/java/com/anytypeio/anytype/ui/database/kanban/KanbanBoardFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/database/kanban/KanbanBoardFragment.kt @@ -2,30 +2,19 @@ package com.anytypeio.anytype.ui.database.kanban import android.os.Bundle import android.view.View -import android.widget.TextView -import androidx.constraintlayout.widget.ConstraintLayout import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModelProviders -import androidx.recyclerview.widget.LinearLayoutManager import com.anytypeio.anytype.R -import com.anytypeio.anytype.core_ui.layout.SpacingItemDecoration -import com.anytypeio.anytype.core_utils.ext.disposedBy import com.anytypeio.anytype.core_utils.ext.px -import com.anytypeio.anytype.core_utils.ext.toast -import com.anytypeio.anytype.core_utils.ui.ViewState import com.anytypeio.anytype.presentation.databaseview.KanbanBoardViewModel -import com.anytypeio.anytype.ui.database.kanban.adapter.KanbanColumnAdapter import com.anytypeio.anytype.ui.database.kanban.helpers.KanbanBoardCallback import com.anytypeio.anytype.ui.database.kanban.helpers.KanbanBoardListener -import io.reactivex.disposables.CompositeDisposable import kotlinx.android.synthetic.main.fragment_kanban.* const val COLUMN_WIDTH = 1.46 // На эту величину делим ширину экрана class KanbanBoardFragment : Fragment(R.layout.fragment_kanban) { - private val subscriptions by lazy { CompositeDisposable() } - private val vm by lazy { ViewModelProviders.of(this).get(KanbanBoardViewModel::class.java) } @@ -59,64 +48,59 @@ class KanbanBoardFragment : Fragment(R.layout.fragment_kanban) { } private fun startObservingViewModel() { - vm.observeKanbanBoard().subscribe { state -> - when (state) { - is ViewState.Success -> { - state.data.forEachIndexed { index, kanbanColumnView -> - val header = - View.inflate( - requireContext(), R.layout.item_kanban_column_header, null - ) - .apply { - findViewById(R.id.columnName).apply { - text = kanbanColumnView.name - (layoutParams as ConstraintLayout.LayoutParams).run { - if (index != 0) this.marginStart = 10.px - } - } - - } - var startSpace = 0 - val space = 10.px - if (index != 0) { - startSpace = 10.px - } - - mBoardView.addColumn( - KanbanColumnAdapter( - kanbanColumnView.rows - ), - header, - header, - true, - LinearLayoutManager(requireContext()) - ) - .apply { - addItemDecoration( - SpacingItemDecoration( - spacingStart = startSpace, - spacingTop = space, - spacingEnd = space, - spacingBottom = space - ) - ) - } - } - } - - is ViewState.Error -> { - requireActivity().toast(state.error) - } - - is ViewState.Loading -> { - TODO() - } - } - }.disposedBy(subscriptions) - } - - override fun onDestroyView() { - super.onDestroyView() - subscriptions.clear() +// vm.observeKanbanBoard().subscribe { state -> +// when (state) { +// is ViewState.Success -> { +// state.data.forEachIndexed { index, kanbanColumnView -> +// val header = +// View.inflate( +// requireContext(), R.layout.item_kanban_column_header, null +// ) +// .apply { +// findViewById(R.id.columnName).apply { +// text = kanbanColumnView.name +// (layoutParams as ConstraintLayout.LayoutParams).run { +// if (index != 0) this.marginStart = 10.px +// } +// } +// +// } +// var startSpace = 0 +// val space = 10.px +// if (index != 0) { +// startSpace = 10.px +// } +// +// mBoardView.addColumn( +// KanbanColumnAdapter( +// kanbanColumnView.rows +// ), +// header, +// header, +// true, +// LinearLayoutManager(requireContext()) +// ) +// .apply { +// addItemDecoration( +// SpacingItemDecoration( +// spacingStart = startSpace, +// spacingTop = space, +// spacingEnd = space, +// spacingBottom = space +// ) +// ) +// } +// } +// } +// +// is ViewState.Error -> { +// requireActivity().toast(state.error) +// } +// +// is ViewState.Loading -> { +// TODO() +// } +// } +// } } } diff --git a/clipboard/build.gradle b/clipboard/build.gradle index f6f6f6f0d7..38c0c5f3b6 100644 --- a/clipboard/build.gradle +++ b/clipboard/build.gradle @@ -52,7 +52,7 @@ dependencies { implementation project(':data') implementation applicationDependencies.kotlin - implementation applicationDependencies.coroutines + implementation applicationDependencies.coroutinesAndroid implementation applicationDependencies.timber testImplementation unitTestDependencies.junit diff --git a/core-ui/build.gradle b/core-ui/build.gradle index 713bff55e0..96b6cd8f04 100644 --- a/core-ui/build.gradle +++ b/core-ui/build.gradle @@ -50,7 +50,7 @@ dependencies { implementation applicationDependencies.appcompat implementation applicationDependencies.kotlin - implementation applicationDependencies.coroutines + implementation applicationDependencies.coroutinesAndroid implementation applicationDependencies.androidxCore implementation applicationDependencies.design diff --git a/core-utils/build.gradle b/core-utils/build.gradle index 6f8e88606d..001c696735 100644 --- a/core-utils/build.gradle +++ b/core-utils/build.gradle @@ -32,7 +32,7 @@ dependencies { implementation applicationDependencies.appcompat implementation applicationDependencies.kotlin - implementation applicationDependencies.coroutines + implementation applicationDependencies.coroutinesAndroid implementation applicationDependencies.dagger implementation applicationDependencies.timber @@ -40,9 +40,6 @@ dependencies { implementation applicationDependencies.constraintLayout - implementation applicationDependencies.rxjava2 - implementation applicationDependencies.rxAndroid - testImplementation unitTestDependencies.junit testImplementation unitTestDependencies.kotlinTest testImplementation unitTestDependencies.mockito diff --git a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/RxExtensions.kt b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/RxExtensions.kt deleted file mode 100644 index 42ead47d98..0000000000 --- a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/ext/RxExtensions.kt +++ /dev/null @@ -1,43 +0,0 @@ -package com.anytypeio.anytype.core_utils.ext - -import io.reactivex.Scheduler -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import io.reactivex.schedulers.TestScheduler - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 02.04.2019. - */ -interface BaseSchedulerProvider { - fun io(): Scheduler - fun computation(): Scheduler - fun ui(): Scheduler -} - -class SchedulerProvider : BaseSchedulerProvider { - override fun computation() = Schedulers.computation() - override fun ui() = AndroidSchedulers.mainThread() - override fun io() = Schedulers.io() -} - -class TrampolineSchedulerProvider : BaseSchedulerProvider { - override fun computation() = Schedulers.trampoline() - override fun ui() = Schedulers.trampoline() - override fun io() = Schedulers.trampoline() -} - -class TestSchedulerProvider(private val scheduler: TestScheduler) : - BaseSchedulerProvider { - override fun computation() = scheduler - override fun ui() = scheduler - override fun io() = scheduler -} - - -fun Disposable.disposedBy(subscriptions: CompositeDisposable) { - subscriptions.add(this) -} diff --git a/dependencies.gradle b/dependencies.gradle index 4f9fb58f5d..10645e541a 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,7 +7,7 @@ allprojects { ext { // Kotlin - kotlin_coroutines_version = '1.3.9' + kotlin_coroutines_version = '1.4.2' kotlinx_serialization_json_version = '1.0.0' // AndroidX @@ -39,13 +39,9 @@ ext { javaxInject_version = '1' retrofit_version = '2.3.0' okhttp_logging_interceptor_version = '3.8.1' - rxjava2_version = '2.1.1' - moshi_version = '1.8.0' gson_version = '2.8.6' - rxrelay_version = '2.1.0' better_link_method_version = '2.2.0' table_view_version = '0.8.9.2' - rxbinding_version = '3.0.0' permission_disp_version = '4.6.0' pickt_version = "0.1.11" zxing_version = "4.1.0" @@ -56,7 +52,7 @@ ext { junit_version = '4.12' mockito_version = '1.4.0' kluent_version = '1.14' - coroutine_testing_version = '1.3.2' + coroutine_testing_version = '1.4.2' live_data_testing_version = '1.1.0' mockito_kotlin_version = '2.2.0' mockito_android_version = '2.25.0' @@ -94,6 +90,7 @@ ext { mainApplication = [ kotlin: "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version", coroutines: "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version", + coroutinesAndroid: "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version", androidxCore: "androidx.core:core-ktx:$androidx_core_version", fragment: "androidx.fragment:fragment-ktx:$fragment_version", navigation: "androidx.navigation:navigation-fragment-ktx:$navigation_version", @@ -120,15 +117,10 @@ ext { javaxAnnotation: "javax.annotation:jsr250-api:$javaxAnnotations_version", javaxInject: "javax.inject:javax.inject:$javaxInject_version", gson: "com.google.code.gson:gson:$gson_version", - rxRelay: "com.jakewharton.rxrelay2:rxrelay:$rxrelay_version", retrofit: "com.squareup.retrofit2:converter-gson:$retrofit_version", okhttpLoggingInterceptor: "com.squareup.okhttp3:logging-interceptor:$okhttp_logging_interceptor_version", timber: "com.jakewharton.timber:timber:$timber_version", - rxjava2: "io.reactivex.rxjava2:rxjava:$rxjava2_version", - rxAndroid: "io.reactivex.rxjava2:rxandroid:$rxjava2_version", - moshiKotlin: "com.squareup.moshi:moshi-kotlin:$moshi_version", tableView: "com.evrencoskun.library:tableview:$table_view_version", - rxBinding: "com.jakewharton.rxbinding3:rxbinding:$rxbinding_version", exoPlayer: "com.google.android.exoplayer:exoplayer:$exoplayer_version", permissionDisp: "org.permissionsdispatcher:permissionsdispatcher:$permission_disp_version", permissionDispCompiler: "org.permissionsdispatcher:permissionsdispatcher-processor:$permission_disp_version", diff --git a/device/build.gradle b/device/build.gradle index 36f4280e8d..531316f7ca 100644 --- a/device/build.gradle +++ b/device/build.gradle @@ -46,7 +46,7 @@ dependencies { implementation project(':data') implementation applicationDependencies.kotlin - implementation applicationDependencies.coroutines + implementation applicationDependencies.coroutinesAndroid implementation applicationDependencies.androidxCore implementation applicationDependencies.timber diff --git a/feature_editor/.gitignore b/feature_editor/.gitignore deleted file mode 100644 index 796b96d1c4..0000000000 --- a/feature_editor/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/feature_editor/build.gradle b/feature_editor/build.gradle deleted file mode 100644 index e1d5c8b257..0000000000 --- a/feature_editor/build.gradle +++ /dev/null @@ -1,70 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' -apply plugin: 'kotlin-kapt' - -android { - def config = rootProject.extensions.getByName("ext") - - compileSdkVersion config["compile_sdk"] - - defaultConfig { - minSdkVersion config["min_sdk"] - targetSdkVersion config["target_sdk"] - testInstrumentationRunner config["test_runner"] - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - buildConfigField "String", "TEST_JSON", '"marks.json"' - } - - debug { - buildConfigField "String", "TEST_JSON", '"marks.json"' - } - } - - sourceSets { main { assets.srcDirs = ['src/main/assets', 'src/main/assets/'] } } - -} - -dependencies { - implementation project(':core-utils') - - def applicationDependencies = rootProject.ext.mainApplication - def unitTestDependencies = rootProject.ext.unitTesting - def acceptenceTesting = rootProject.ext.acceptanceTesting - - kapt applicationDependencies.daggerCompiler - compileOnly applicationDependencies.javaxInject - - implementation applicationDependencies.kotlin - implementation applicationDependencies.viewModel - implementation applicationDependencies.viewModelExtensions - implementation applicationDependencies.appcompat - implementation applicationDependencies.design - implementation applicationDependencies.constraintLayout - implementation applicationDependencies.recyclerView - - implementation applicationDependencies.rxjava2 - implementation applicationDependencies.rxRelay - implementation applicationDependencies.rxAndroid - implementation applicationDependencies.dagger - implementation applicationDependencies.timber - implementation applicationDependencies.gson - implementation applicationDependencies.betterLinkMovement - - implementation applicationDependencies.glide - - kapt applicationDependencies.glideCompiler - - testImplementation unitTestDependencies.junit - testImplementation unitTestDependencies.kotlinTest - testImplementation unitTestDependencies.mockito - - androidTestImplementation acceptenceTesting.espressoCore - androidTestImplementation acceptenceTesting.androidJUnit - androidTestImplementation acceptenceTesting.testRules -} diff --git a/feature_editor/proguard-rules.pro b/feature_editor/proguard-rules.pro deleted file mode 100644 index f1b424510d..0000000000 --- a/feature_editor/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# 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 *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile diff --git a/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/BlockModelMapperTest.kt b/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/BlockModelMapperTest.kt deleted file mode 100644 index 9c3a409ef0..0000000000 --- a/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/BlockModelMapperTest.kt +++ /dev/null @@ -1,251 +0,0 @@ -package com.agileburo.anytype.feature_editor - -import android.graphics.Typeface -import android.text.SpannableString -import android.text.style.StrikethroughSpan -import android.text.style.StyleSpan -import androidx.test.runner.AndroidJUnit4 -import com.agileburo.anytype.feature_editor.domain.* -import com.agileburo.anytype.feature_editor.factory.AndroidDataFactory -import com.agileburo.anytype.feature_editor.presentation.mapper.BlockModelMapper -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import junit.framework.Assert.assertEquals -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 2019-05-15. - */ -class BlockModelMapperTest { - - lateinit var blockMapper: BlockModelMapper - - val BOLD = "BOLD" - val ITALIC = "ITALIC" - val STRIKE = "STRIKE_THROUGH" - - val spannableText = SpannableString("This can be simply solved by using Spannable String").apply { - setSpan(StyleSpan(Typeface.BOLD), 0, 3, 0) - setSpan(StyleSpan(Typeface.BOLD), 19, 24, 0) - setSpan(StyleSpan(Typeface.ITALIC), 12, 17, 0) - setSpan(StrikethroughSpan(), 27, 33, 0) - } - - val blockView = BlockView.ParagraphView( - id = "2321", - text = spannableText - ) - - @Before - fun init() { - blockMapper = BlockModelMapper() - } - - @Test - fun testShouldBeTheSameMarks() { - val block = blockMapper.mapToModel(blockView) - val content = block.content as Content.Text - - assertEquals(4, content.marks.size) - assertEquals(3, content.marks[0].end) - assertEquals(BOLD, content.marks[0].type.name) - assertEquals(24, content.marks[1].end) - assertEquals(BOLD, content.marks[1].type.name) - assertEquals(12, content.marks[2].start) - assertEquals(ITALIC, content.marks[2].type.name) - assertEquals(33, content.marks[3].end) - assertEquals(STRIKE, content.marks[3].type.name) - } - - @Test - fun paragraphViewConvertedCorrectly() { - - val view = BlockView.ParagraphView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()) - ) - - val block = blockMapper.mapToModel(view) - val content = block.content as Content.Text - - assertEquals(view.text.toString(), content.text) - assertEquals(view.id, view.id) - assertEquals(block.blockType, BlockType.Editable) - assertEquals(block.contentType, ContentType.P) - } - - @Test - fun bulletViewConvertedCorrectly() { - - val view = BlockView.BulletView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()) - ) - - val block = blockMapper.mapToModel(view) - val content = block.content as Content.Text - - assertEquals(view.text.toString(), content.text) - assertEquals(view.id, view.id) - assertEquals(block.blockType, BlockType.Editable) - assertEquals(block.contentType, ContentType.UL) - } - - @Test - fun quoteViewConvertedCorrectly() { - - val view = BlockView.QuoteView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()) - ) - - val block = blockMapper.mapToModel(view) - val content = block.content as Content.Text - - assertEquals(view.text.toString(), content.text) - assertEquals(view.id, view.id) - assertEquals(block.blockType, BlockType.Editable) - assertEquals(block.contentType, ContentType.Quote) - } - - @Test - fun checkboxViewConvertedCorrectly() { - - val view = BlockView.CheckboxView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()), - isChecked = AndroidDataFactory.randomBoolean() - ) - - val block = blockMapper.mapToModel(view) - val content = block.content as Content.Text - - assertEquals(view.text.toString(), content.text) - assertEquals(view.id, view.id) - assertEquals(block.blockType, BlockType.Editable) - assertEquals(block.contentType, ContentType.Check) - assertEquals(content.param.checked, view.isChecked) - } - - @Test - fun numberedListItemConvertedCorrectly() { - - val view = BlockView.NumberListItemView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()), - number = AndroidDataFactory.randomInt() - ) - - val block = blockMapper.mapToModel(view) - val content = block.content as Content.Text - - assertEquals(view.text.toString(), content.text) - assertEquals(view.id, view.id) - assertEquals(block.blockType, BlockType.Editable) - assertEquals(block.contentType, ContentType.NumberedList) - assertEquals(content.param.number, view.number) - } - - @Test - fun codeSnippetViewConvertedCorrectly() { - - val view = BlockView.CodeSnippetView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()) - ) - - val block = blockMapper.mapToModel(view) - val content = block.content as Content.Text - - assertEquals(view.text.toString(), content.text) - assertEquals(view.id, view.id) - assertEquals(block.blockType, BlockType.Editable) - assertEquals(block.contentType, ContentType.Code) - } - - @Test - fun headerOneViewConvertedCorrectly() { - - val headerOneView = BlockView.HeaderView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()), - type = BlockView.HeaderView.HeaderType.ONE - ) - - - val headerOneBlock = blockMapper.mapToModel(headerOneView) - val content = headerOneBlock.content as Content.Text - - - assertEquals(headerOneView.text.toString(), content.text) - assertEquals(headerOneView.id, headerOneView.id) - assertEquals(headerOneBlock.blockType, BlockType.Editable) - assertEquals(headerOneBlock.contentType, ContentType.H1) - - } - - @Test - fun headerTwoViewConvertedCorrectly() { - - val headerTwoView = BlockView.HeaderView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()), - type = BlockView.HeaderView.HeaderType.TWO - ) - - val headerTwoBlock = blockMapper.mapToModel(headerTwoView) - val content = headerTwoBlock.content as Content.Text - - - assertEquals(headerTwoView.text.toString(), content.text) - assertEquals(headerTwoView.id, headerTwoView.id) - assertEquals(headerTwoBlock.blockType, BlockType.Editable) - assertEquals(headerTwoBlock.contentType, ContentType.H2) - - } - - @Test - fun headerThreeViewConvertedCorrectly() { - - val headerThreeView = BlockView.HeaderView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()), - type = BlockView.HeaderView.HeaderType.THREE - ) - - val headerThreeBlock = blockMapper.mapToModel(headerThreeView) - val content = headerThreeBlock.content as Content.Text - - - assertEquals(headerThreeView.text.toString(), content.text) - assertEquals(headerThreeView.id, headerThreeView.id) - assertEquals(headerThreeBlock.blockType, BlockType.Editable) - assertEquals(headerThreeBlock.contentType, ContentType.H3) - - } - - @Test - fun headerFourViewConvertedCorrectly() { - - val headerFourView = BlockView.HeaderView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()), - type = BlockView.HeaderView.HeaderType.FOUR - ) - - val headerFourBlock = blockMapper.mapToModel(headerFourView) - val content = headerFourBlock.content as Content.Text - - - assertEquals(headerFourView.text.toString(), content.text) - assertEquals(headerFourView.id, headerFourView.id) - assertEquals(headerFourBlock.blockType, BlockType.Editable) - assertEquals(headerFourBlock.contentType, ContentType.H4) - - } - - -} \ No newline at end of file diff --git a/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/BlockViewDiffUtilTest.kt b/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/BlockViewDiffUtilTest.kt deleted file mode 100644 index 52b8472c77..0000000000 --- a/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/BlockViewDiffUtilTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.agileburo.anytype.feature_editor - -import android.text.SpannableString -import androidx.recyclerview.widget.DiffUtil -import com.agileburo.anytype.feature_editor.factory.AndroidDataFactory -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import com.agileburo.anytype.feature_editor.presentation.util.BlockViewDiffUtil -import org.junit.Assert -import org.junit.Before -import org.junit.Test - -class BlockViewDiffUtilTest { - - - private lateinit var diffUtil : DiffUtil.Callback - - @Before - fun init() { - - val firstBlock = BlockView.ParagraphView( - id = AndroidDataFactory.randomString(), - text = SpannableString(AndroidDataFactory.randomString()) - ) - - val second = firstBlock.copy() - - diffUtil = BlockViewDiffUtil(listOf(firstBlock), listOf(second)) - } - - @Test - fun blocksShouldBeTheSame() { - val result = diffUtil.areItemsTheSame(0, 0) - assert(result) - } - - @Test - fun blockShouldBeEquals() { - val result = diffUtil.areContentsTheSame(0,0) - Assert.assertTrue(result) - } - -} \ No newline at end of file diff --git a/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/factory/AndroidDataFactory.kt b/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/factory/AndroidDataFactory.kt deleted file mode 100644 index 6255c3d05c..0000000000 --- a/feature_editor/src/androidTest/java/com/agileburo/anytype/feature_editor/factory/AndroidDataFactory.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.agileburo.anytype.feature_editor.factory - -import java.util.* -import java.util.concurrent.ThreadLocalRandom - -object AndroidDataFactory { - - fun randomUuid(): String { - return UUID.randomUUID().toString() - } - - fun randomString(): String { - return randomUuid() - } - - fun randomInt(): Int { - return ThreadLocalRandom.current().nextInt(0, 1000 + 1) - } - - fun randomInt(min : Int = 0, max: Int): Int { - return ThreadLocalRandom.current().nextInt(min, max) - } - - fun randomLong(): Long { - return randomInt().toLong() - } - - fun randomFloat(): Float { - return randomInt().toFloat() - } - - fun randomDouble(): Double { - return randomInt().toDouble() - } - - fun randomBoolean(): Boolean { - return Math.random() < 0.5 - } - - fun makeStringList(count: Int): List { - val items = mutableListOf() - repeat(count) { - items.add(randomUuid()) - } - return items - } - -} \ No newline at end of file diff --git a/feature_editor/src/main/AndroidManifest.xml b/feature_editor/src/main/AndroidManifest.xml deleted file mode 100644 index 9960257403..0000000000 --- a/feature_editor/src/main/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - diff --git a/feature_editor/src/main/assets/dnd.json b/feature_editor/src/main/assets/dnd.json deleted file mode 100644 index e488b3bcf7..0000000000 --- a/feature_editor/src/main/assets/dnd.json +++ /dev/null @@ -1,78 +0,0 @@ - -{ - "blocks": [ - { - "id": "c0301f2b-b532-55e1-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Первый", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "fdresaf2b-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Третий", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "ytewty6q-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Пятый", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "6ytewty6q-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Шестой", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "7ytewty6q-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Седьмой", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "8ytewty6q-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Восьмой", - "marks": [] - }, - "width": 0, - "children": [] - } - ] -} - diff --git a/feature_editor/src/main/assets/edit.json b/feature_editor/src/main/assets/edit.json deleted file mode 100644 index c24371cd29..0000000000 --- a/feature_editor/src/main/assets/edit.json +++ /dev/null @@ -1,42 +0,0 @@ - -{ - "blocks": [ - { - "id": "c0301f2b-b532-55e1-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Первый", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "fdresaf2b-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Третий", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "ytewty6q-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 11, - "content": { - "text": "Пятый", - "marks": [] - }, - "width": 0, - "children": [] - } - ] -} - diff --git a/feature_editor/src/main/assets/marks.json b/feature_editor/src/main/assets/marks.json deleted file mode 100644 index cf3a87c9ae..0000000000 --- a/feature_editor/src/main/assets/marks.json +++ /dev/null @@ -1,365 +0,0 @@ -{ - "blocks": [ - { - "id": "0", - "parentId": "", - "type": 3, - "contentType": 3, - "content": {"text":"Разработка AnyType","marks":[]}, - "width": 0, - "children": [] - }, - { - "id":"1", - "parentId":"", - "type":6, - "contentType":0, - "content":{ - "original":{ - "key":"TACT7msSX8vkkFBhanRYT2wkA77hjfowo7WGyrrL9SEeEVEixy3LpDwp8j46", - "type":"image/jpeg", - "name":"1280px-Francesco_Salviati_005.jpg", - "hash":"QmXzbG8L8aeZ3VUnMJDJzVCKNTf1MMrGPdUsgsR2F3f3vu", - "size":311430, - "time":1558123043583 - }, - "size":{ - "width":770, - "div":0.73 - } - }, - "width":0, - "children":[ - - ] - }, - { - "id":"2", - "parentId":"", - "type": 3, - "contentType": 9, - "content":{"text":"First toggle","marks":[]}, - "width": 0, - "children":[ - { - "id":"3", - "parentId":"2", - "type": 3, - "contentType": 1, - "content":{"text":"First toggle first paragraph","marks":[]}, - "width": 0, - "children": [] - }, - { - "id":"4", - "parentId":"2", - "type": 3, - "contentType": 9, - "content":{"text":"Second toggle","marks":[]}, - "width": 0, - "children": [ - { - "id":"5", - "parentId":"4", - "type": 3, - "contentType": 1, - "content":{"text":"Second toggle first paragraph","marks":[]}, - "width": 0, - "children": [] - }, - { - "id":"6", - "parentId":"4", - "type": 3, - "contentType": 1, - "content":{"text":"Second toggle second paragraph","marks":[]}, - "width": 0, - "children": [] - }, - { - "id":"7", - "parentId":"4", - "type": 3, - "contentType": 9, - "content":{"text":"Third toggle","marks":[]}, - "width": 0, - "children": [ - { - "id":"8", - "parentId":"7", - "type": 3, - "contentType": 1, - "content":{"text":"Third toggle first paragraph","marks":[]}, - "width": 0, - "children": [] - }, - { - "id":"9", - "parentId":"7", - "type": 3, - "contentType": 1, - "content":{"text":"Third toggle second paragraph","marks":[]}, - "width": 0, - "children": [] - } - ] - } - ] - } - ] - }, - { - "id": "10", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Так говорила в июле 1805 года известная Анна Павловна Шерер, фрейлина и приближенная императрицы Марии Феодоровны, встречая важного и чиновного князя Василия, первого приехавшего на ее вечер. Анна Павловна кашляла несколько дней, у нее был грипп,как она говорила (грипп был тогда новое слово, употреблявшееся только редкими). В записочках, разосланных утрoом с красным лакеем, было написано без различия во всех:", - "marks": [ - { - "type": "i", - "start": 240, - "end": 246 - }, - { - "type": "i", - "start": 264, - "end": 269 - }, - { - "type": "b", - "start": 340, - "end": 374 - }, - { - "type": "i", - "start": 150, - "end": 157 - }, - { - "type": "i", - "start": 40, - "end": 59 - }, - { - "type": "i", - "start": 97, - "end": 113 - }, - { - "type": "i", - "start": 192, - "end": 205 - }, - { - "type": "b", - "start": 167, - "end": 178 - }, - { - "type": "b", - "start": 125, - "end": 130 - }, - { - "type": "s", - "start": 254, - "end": 259 - }, - { - "type": "i", - "start": 397, - "end": 402 - }, - { - "type": "kbd", - "start": 328, - "end": 338 - }, - { - "type": "a", - "start": 316, - "end": 323, - "param": "https://yandex.ru/" - } - ] - }, - "width": 0, - "children": [] - }, - { - "id": "11", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "«Si vous n'avez rien de mieux à faire, Monsieur le comte (или mon prince), et si la perspective de passer la soirée chez une pauvre malade ne vous effraye pas trop, je serai charmée de vous voir chez moi entre 7 et 10 heures. Annette Scherer» ", - "marks": [ - { - "type": "s", - "start": 0, - "end": 242 - } - ] - }, - "width": 0, - "children": [] - }, - { - "id": "12", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Dieu, quelle virulente sortie! — отвечал, нисколько не смутясь такою встречей, вошедший князь, в придворном, шитом мундире, в чулках, башмаках и звездах, с светлым выражением плоского лица.", - "marks": [ - { - "type": "a", - "param": "https://ilibrary.ru/text/11/p.1/index.html#fn4", - "start": 0, - "end": 30 - }, - { - "type": "b", - "start": 33, - "end": 40 - } - ] - }, - "width": 0, - "children": [] - }, - { - "id": "13", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Жена узнала, что муж был в связи с бывшею в их доме француженкою-гувернанткой, и объявила мужу, что не может жить с ним в одном доме. ", - "marks": [] - }, - "children": [] - }, - { - "id": "14", - "parentId": "", - "type": 3, - "contentType": 10, - "content": { - "text": "На третий день после ссоры князь Степан Аркадьич Облонский — Стива, как его звали в свете, — в обычный час, то есть в восемь часов утра, проснулся не в спальне жены, а в своем кабинете, на сафьянном диване.", - "marks": [] - }, - "children": [] - }, - { - "id": "15", - "parentId": "", - "type": 3, - "contentType": 2, - "content": { - "text": "Он повернул свое полное, выхоленное тело на пружинах дивана, как бы желая опять заснуть надолго, с другой стороны крепко обнял подушку и прижался к ней щекой; но вдруг вскочил, сел на диван и открыл глаза.", - "marks": [] - }, - "children": [] - }, - { - "id": "16", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "«Да, да, как это было? — думал он, вспоминая сон.", - "marks": [] - }, - "children": [] - }, - { - "id": "17", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Первый", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "18", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Третий", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "19", - "parentId": "", - "type": 3, - "contentType": 11, - "content": { - "text": "Пятый", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "20", - "parentId": "", - "type": 7, - "contentType": 0, - "content": { - "id": "12D3KooWRUkB3qUaxiz1VCGP3Uoy4jv8Nx7kCKdMSuhmXqwsjMJ6" - }, - "width": 0, - "children": [] - }, - { - "id":"21", - "parentId":"", - "type":4, - "contentType":0, - "content":"", - "width":0, - "children":[ - - ] - }, - { - "id": "22", - "parentId": "", - "type": 9, - "contentType": 0, - "content": { - "bookMark": { - "type": "profile", - "url": "https://rateyourmusic.com/artist/the_tallest_man_on_earth", - "title": "The Tallest Man on Earth discography", - "description": "The Tallest Man on Earth discography and songs: Music profile for The Tallest Man on Earth, born 30 April 1983. Genres: Contemporary Folk, Singer/Songwriter, Indie Folk. Albums include The Wild Hunt, Shallow Grave, and There's No Leaving Now.", - "site": "RateYourMusic", - "icon": "", - "images": [ - { - "url": "https://e.snmc.io/i/600/s/a9eec69d93bfd25142741293d34de3f8/4095112", - "secure": "", - "type": "", - "width": 0, - "height": 0 - } - ], - "audios": [], - "videos": [] - } - }, - "width": 0, - "children": [] - } - ] -} - diff --git a/feature_editor/src/main/assets/test.json b/feature_editor/src/main/assets/test.json deleted file mode 100644 index ef63af7152..0000000000 --- a/feature_editor/src/main/assets/test.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "blocks": [ - { - "id": "1cb83d95-7913-5c2e-99e8-1272110ab38f", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Все счастливые семьи похожи друг на друга, каждая несчастливая семья несчастлива по-своему.", - "marks": [] - }, - "children": [] - }, - { - "id": "02ca4410-2cff-5978-81e5-09dc76dd003c", - "parentId": "", - "type": 3, - "contentType": 4, - "content": { - "text": "Все смешалось в доме Облонских.", - "marks": [] - }, - "children": [] - }, - { - "id": "116271cc-c6e3-5c58-8598-9342567b9a66", - "parentId": "", - "type": 3, - "contentType": 5, - "content": { - "text": "Жена узнала, что муж был в связи с бывшею в их доме француженкою-гувернанткой, и объявила мужу, что не может жить с ним в одном доме. ", - "marks": [] - }, - "children": [] - }, - { - "id": "567980cc-fght-wedr-5679-9342567b9a76", - "parentId": "", - "type": 3, - "contentType": 11, - "content": { - "text": "Положение это продолжалось уже третий день и мучительно чувствовалось и самими супругами, и всеми членами семьи, и домочадцами.", - "marks": [] - }, - "children": [] - }, - { - "id": "93f8810e-590f-5962-a662-2c1fe17e5cbe", - "parentId": "", - "type": 1, - "contentType": 0, - "content": {}, - "children": [ - { - "id": "22a8f9f5-b042-5532-bb5d-cbda07f579e0", - "parentId": "93f8810e-590f-5962-a662-2c1fe17e5cbe", - "type": 3, - "contentType": 8, - "content": { - "text": "Все члены семьи и домочадцы чувствовали, что нет смысла в их сожительстве и что на каждом постоялом дворе случайно сошедшиеся люди более связаны между собой, чем они, члены семьи и домочадцы Облонских.", - "marks": [] - }, - "children": [ - { - "id": "1983", - "parentId": "92152a56-40d3-53ec-a1fa-ec4e4d92b0ec", - "type": 3, - "contentType": 7, - "content": { - "text": "Жена не выходила из своих комнат, мужа третий день не было дома.", - "marks": [] - }, - "children": [] - } - ] - }, - { - "id": "92152a56-40d3-53ec-a1fa-ec4e4d92b0ec", - "parentId": "93f8810e-590f-5962-a662-2c1fe17e5cbe", - "type": 3, - "contentType": 6, - "content": { - "text": "Дети бегали по всему дому, как потерянные; англичанка поссорилась с экономкой и написала записку приятельнице, прося приискать ей новое место; повар ушел вчера со двора, во время самого обеда; черная кухарка и кучер просили расчета.", - "marks": [], - "number": 1 - }, - "children": [] - } - ] - }, - { - "id": "21fe093a-5f74-583b-9c17-ee798e1bfc7e", - "parentId": "", - "type": 3, - "contentType": 10, - "content": { - "text": "На третий день после ссоры князь Степан Аркадьич Облонский — Стива, как его звали в свете, — в обычный час, то есть в восемь часов утра, проснулся не в спальне жены, а в своем кабинете, на сафьянном диване.", - "marks": [] - }, - "children": [] - }, - { - "id": "f0c40441-2a3f-5150-bad3-e0d43c72a997", - "parentId": "", - "type": 3, - "contentType": 2, - "content": { - "text": "Он повернул свое полное, выхоленное тело на пружинах дивана, как бы желая опять заснуть надолго, с другой стороны крепко обнял подушку и прижался к ней щекой; но вдруг вскочил, сел на диван и открыл глаза.", - "marks": [] - }, - "children": [] - }, - { - "id": "01f2a219-94ba-5bd6-a48e-5b9af61e1a10", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "«Да, да, как это было? — думал он, вспоминая сон.", - "marks": [] - }, - "children": [] - }, - { - "id": "c0301f2b-b532-55e1-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Первый", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "fdresaf2b-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 1, - "content": { - "text": "Третий", - "marks": [] - }, - "width": 0, - "children": [] - }, - { - "id": "ytewty6q-b532-5345-92ba-2b2fc4af237e", - "parentId": "", - "type": 3, - "contentType": 11, - "content": { - "text": "Пятый", - "marks": [] - }, - "width": 0, - "children": [] - } - ] -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/EditorDi.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/EditorDi.kt deleted file mode 100644 index b6dae805c8..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/EditorDi.kt +++ /dev/null @@ -1,89 +0,0 @@ -package com.agileburo.anytype.feature_editor - -import android.content.Context -import com.agileburo.anytype.core_utils.di.scope.PerFeature -import com.agileburo.anytype.core_utils.ext.BaseSchedulerProvider -import com.agileburo.anytype.feature_editor.data.* -import com.agileburo.anytype.feature_editor.data.datasource.BlockDataSource -import com.agileburo.anytype.feature_editor.data.datasource.IPFSDataSourceImpl -import com.agileburo.anytype.feature_editor.data.parser.ContentModelParser -import com.agileburo.anytype.feature_editor.domain.EditorInteractor -import com.agileburo.anytype.feature_editor.domain.EditorInteractorImpl -import com.agileburo.anytype.feature_editor.presentation.converter.BlockContentTypeConverter -import com.agileburo.anytype.feature_editor.presentation.converter.BlockContentTypeConverterImpl -import com.agileburo.anytype.feature_editor.presentation.mvvm.EditorViewModelFactory -import com.agileburo.anytype.feature_editor.ui.EditorFragment -import com.google.gson.Gson -import com.google.gson.GsonBuilder -import dagger.Module -import dagger.Provides -import dagger.Subcomponent - -@PerFeature -@Subcomponent(modules = [EditorModule::class]) -interface EditorComponent { - - fun inject(fragment: EditorFragment) -} - -@Module -@PerFeature -class EditorModule { - - @Provides - @PerFeature - fun provideGson(): Gson = GsonBuilder().create() - - @Provides - @PerFeature - fun provideBlockConverter( - contentConverter: ContentConverter, - contentModelParser : ContentModelParser - ): BlockConverter = - BlockConverterImpl(contentConverter = contentConverter, contentModelParser = contentModelParser) - - @Provides - @PerFeature - fun provideRepo(blockConverter: BlockConverter, dataSource: BlockDataSource): EditorRepo = - EditorRepoImpl(dataSource = dataSource, blockConverter = blockConverter) - - @Provides - @PerFeature - fun provideInteractor(repo: EditorRepo): EditorInteractor = EditorInteractorImpl(repo = repo) - - @Provides - @PerFeature - fun provideDataSource(context: Context, gson: Gson): BlockDataSource = - IPFSDataSourceImpl(context = context, gson = gson) - - @Provides - @PerFeature - fun provideFactory( - interactor: EditorInteractor, - contentTypeConverter: BlockContentTypeConverter, - baseSchedulerProvider: BaseSchedulerProvider - ): EditorViewModelFactory = - EditorViewModelFactory(interactor, contentTypeConverter, baseSchedulerProvider) - - @Provides - @PerFeature - fun provideBlockContentConverter(markConverter: MarkConverter): ContentConverter = - ContentConverterImpl(markConverter = markConverter) - - @Provides - @PerFeature - fun provideMarkConverter(): MarkConverter = MarkConverterImpl() - - @Provides - @PerFeature - fun provideContentModelParser(gson : Gson) : ContentModelParser { - return ContentModelParser(gson) - } - - @Provides - @PerFeature - fun provideContentTypeConverter(): BlockContentTypeConverter = - BlockContentTypeConverterImpl() - - -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/Extensions.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/Extensions.kt deleted file mode 100644 index 683ff8944f..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/Extensions.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.agileburo.anytype.feature_editor - -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 21.03.2019. - */ - -fun Disposable.disposedBy(subscriptions: CompositeDisposable) { - subscriptions.add(this) -} diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/BlockConverter.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/BlockConverter.kt deleted file mode 100644 index afde7ddca9..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/BlockConverter.kt +++ /dev/null @@ -1,198 +0,0 @@ -package com.agileburo.anytype.feature_editor.data - -import com.agileburo.anytype.feature_editor.data.converter.toBlockType -import com.agileburo.anytype.feature_editor.data.converter.toContentType -import com.agileburo.anytype.feature_editor.data.parser.ContentModelParser -import com.agileburo.anytype.feature_editor.domain.Block -import com.agileburo.anytype.feature_editor.domain.BlockType -import com.agileburo.anytype.feature_editor.domain.Content -import com.agileburo.anytype.feature_editor.domain.ContentType - - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 20.03.2019. - */ -interface BlockConverter { - fun modelToDomain(model: BlockModel): Block - fun modelTreeToDomainTree(model: BlockModel): Block -} - -class BlockConverterImpl( - private val contentConverter: ContentConverter, - private val contentModelParser: ContentModelParser -) : BlockConverter { - - override fun modelTreeToDomainTree(model: BlockModel): Block { - - val type = model.type.toBlockType() - - when (type) { - is BlockType.Editable -> { - - val parsed = contentModelParser.parse(model.content, type) - - val content = contentConverter.modelToDomain(parsed as ContentModel.Text) - - return Block( - id = model.id, - content = content, - parentId = model.parentId, - contentType = model.contentType.toContentType(), - blockType = model.type.toBlockType(), - children = model.children.map { modelTreeToDomainTree(it) }.toMutableList() - ) - - } - is BlockType.Page -> { - - val parsed = contentModelParser.parse(model.content, type) - - val content = contentConverter.modelToDomain(parsed as ContentModel.Page) - - return Block( - id = model.id, - content = content, - parentId = model.parentId, - contentType = model.contentType.toContentType(), - blockType = model.type.toBlockType(), - children = model.children.map { modelTreeToDomainTree(it) }.toMutableList() - ) - - } - - is BlockType.BookMark -> { - - val parsed = contentModelParser.parse(model.content, type) - - val content = contentConverter.modelToDomain(parsed as ContentModel.Bookmark) - - return Block( - id = model.id, - content = content, - parentId = model.parentId, - contentType = model.contentType.toContentType(), - blockType = model.type.toBlockType(), - children = model.children.map { modelTreeToDomainTree(it) }.toMutableList() - ) - - } - - is BlockType.Divider -> { - - return Block( - id = model.id, - parentId = model.parentId, - contentType = ContentType.None, - content = Content.Empty, - blockType = BlockType.Divider, - children = model.children.map { modelTreeToDomainTree(it) }.toMutableList() - ) - - } - - is BlockType.Image -> { - - val parsed = contentModelParser.parse(model.content, type) as ContentModel.Image - val content = contentConverter.modelToDomain(parsed) - - return Block( - id = model.id, - parentId = model.parentId, - content = content, - contentType = ContentType.None, - blockType = BlockType.Image, - children = model.children.map { modelTreeToDomainTree(it) }.toMutableList() - ) - } - - else -> TODO() - - } - - } - - override fun modelToDomain(model: BlockModel): Block { - - val type = model.type.toBlockType() - - when (type) { - is BlockType.Editable -> { - - val parsed = contentModelParser.parse(model.content, type) - - val content = contentConverter.modelToDomain(parsed as ContentModel.Text) - - return Block( - id = model.id, - content = content, - parentId = model.parentId, - contentType = model.contentType.toContentType(), - blockType = model.type.toBlockType() - ) - - } - is BlockType.Page -> { - - val parsed = contentModelParser.parse(model.content, type) - - val content = contentConverter.modelToDomain(parsed as ContentModel.Page) - - return Block( - id = model.id, - content = content, - parentId = model.parentId, - contentType = model.contentType.toContentType(), - blockType = model.type.toBlockType() - ) - - } - - is BlockType.BookMark -> { - - val parsed = contentModelParser.parse(model.content, type) - - val content = contentConverter.modelToDomain(parsed as ContentModel.Bookmark) - - return Block( - id = model.id, - content = content, - parentId = model.parentId, - contentType = model.contentType.toContentType(), - blockType = model.type.toBlockType() - ) - - } - - is BlockType.Divider -> { - - return Block( - id = model.id, - parentId = model.parentId, - contentType = ContentType.None, - content = Content.Empty, - blockType = BlockType.Divider - ) - - } - - is BlockType.Image -> { - - val parsed = contentModelParser.parse(model.content, type) as ContentModel.Image - val content = contentConverter.modelToDomain(parsed) - - return Block( - id = model.id, - parentId = model.parentId, - content = content, - contentType = ContentType.None, - blockType = BlockType.Image - ) - } - - else -> TODO() - } - } - -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/BlockModel.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/BlockModel.kt deleted file mode 100644 index 7d9096735a..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/BlockModel.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.agileburo.anytype.feature_editor.data - -import com.google.gson.JsonElement - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 20.03.2019. - */ -data class BlockModel( - val id: String, - val parentId: String = "", - val content: JsonElement, - val contentType: Int, - val type: Int, - val children: List -) diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/ContentConverter.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/ContentConverter.kt deleted file mode 100644 index 821896cfba..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/ContentConverter.kt +++ /dev/null @@ -1,65 +0,0 @@ -package com.agileburo.anytype.feature_editor.data - -import com.agileburo.anytype.feature_editor.domain.Content -import com.agileburo.anytype.feature_editor.domain.ContentParam - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 25.03.2019. - */ -interface ContentConverter { - fun modelToDomain(model: ContentModel.Text): Content.Text - fun domainToModel(domain: Content.Text): ContentModel.Text - fun modelToDomain(model : ContentModel.Page) : Content.Page - fun modelToDomain(model : ContentModel.Bookmark) : Content.Bookmark - fun modelToDomain(model : ContentModel.Image) : Content.Picture -} - -class ContentConverterImpl(private val markConverter: MarkConverter) : ContentConverter { - - override fun modelToDomain(model: ContentModel.Text) = - Content.Text( - text = model.text, - marks = model.marks.map { markConverter.modelToDomain(it) }, - param = ContentParam( - mutableMapOf( - "number" to (model.number ?: 0), - "checked" to (model.checked ?: false) - ) - ) - ) - - //TODO add marks convert! - override fun domainToModel(domain: Content.Text) = - ContentModel.Text( - text = domain.text.toString(), - marks = domain.marks.map { markConverter.domainToModel(it) }, - number = domain.param.number, - checked = domain.param.checked - ) - - override fun modelToDomain(model: ContentModel.Page): Content.Page { - return Content.Page(model.id) - } - - override fun modelToDomain(model: ContentModel.Bookmark): Content.Bookmark { - return Content.Bookmark( - type = model.bookMark.type, - description = model.bookMark.description, - title = model.bookMark.title, - url = model.bookMark.url, - site = model.bookMark.site, - icon = model.bookMark.icon, - images = model.bookMark.images.map { image -> Content.Bookmark.Image(image.url) } - ) - } - - override fun modelToDomain(model: ContentModel.Image): Content.Picture { - // TODO remove hard-coded - return Content.Picture( - url = "https://c.wallhere.com/photos/6c/31/vintage_typewriters_books_glasses_wood_paper_pine_cones-727921.jpg!d", - type = Content.Picture.Type.ORIGINAL - ) - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/ContentModel.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/ContentModel.kt deleted file mode 100644 index b102e42066..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/ContentModel.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.agileburo.anytype.feature_editor.data - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 25.03.2019. - */ -sealed class ContentModel { - - data class Text( - val text: String = "", - val marks: List = emptyList(), - val number : Int? = null, - val checked : Boolean? = null - ) : ContentModel() - - data class Page( - val id : String - ) : ContentModel() - - data class Bookmark( - val bookMark : BookmarkModel - ) : ContentModel() - - data class BookmarkModel( - val type : String, - val url : String, - val title : String, - val description : String, - val site : String, - val icon : String, - val images : List - ) - - data class Image( - val original : OriginalImageModel - ) : ContentModel() - - data class OriginalImageModel( - val key : String, - val type : String, - val name : String, - val size : Int, - val time : Long - ) - - data class ImageModel(val url : String) - -} diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/EditorRepo.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/EditorRepo.kt deleted file mode 100644 index a9bca3f969..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/EditorRepo.kt +++ /dev/null @@ -1,44 +0,0 @@ -package com.agileburo.anytype.feature_editor.data - -import com.agileburo.anytype.feature_editor.data.datasource.BlockDataSource -import com.agileburo.anytype.feature_editor.domain.Block -import io.reactivex.Single -import javax.inject.Inject - -interface EditorRepo { - - fun getBlocks(): Single> - fun saveState(list: List) -} - -class EditorRepoImpl @Inject constructor( - private val dataSource: BlockDataSource, - private val blockConverter: BlockConverter -) : EditorRepo { - - override fun getBlocks(): Single> { - return dataSource.getBlocks().map { it.map(blockConverter::modelTreeToDomainTree) } - } - - override fun saveState(list: List) { - wrap(list) - } - - // TODO перевести в отдельный маппер, пусть репозиторий отвечает толька за CRUD-операции - private fun unwrap(blocks: List): List { - val result = mutableListOf() - if (blocks.isEmpty()) return result - blocks.forEach { - result.add(blockConverter.modelToDomain(it)) - if (it.children.isNotEmpty()) { - result.addAll(unwrap(it.children)) - } - } - return result - } - - //TODO предполагаем, что понадобится перевод листа блоков в дерево для отдачи беку - private fun wrap(list: List): List { - return emptyList() - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/MarkConverter.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/MarkConverter.kt deleted file mode 100644 index 2b93a8aed0..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/MarkConverter.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.agileburo.anytype.feature_editor.data - -import android.net.MacAddress -import com.agileburo.anytype.feature_editor.domain.Mark - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 03.04.2019. - */ -interface MarkConverter { - - fun modelToDomain(model: MarkModel): Mark - fun domainToModel(domain: Mark): MarkModel -} - -class MarkConverterImpl : MarkConverter { - - override fun modelToDomain(model: MarkModel): Mark = - Mark(type = getType(model.type), - start = model.start, - end = model.end, - param = model.param) - - override fun domainToModel(domain: Mark): MarkModel { - throw UnsupportedOperationException("not implemented") - } - - private fun getType(type: String) = - when (type) { - "b" -> Mark.MarkType.BOLD - "i" -> Mark.MarkType.ITALIC - "s" -> Mark.MarkType.STRIKE_THROUGH - "kbd" -> Mark.MarkType.CODE - "a" -> Mark.MarkType.HYPERTEXT - else -> Mark.MarkType.UNDEFINED - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/MarkModel.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/MarkModel.kt deleted file mode 100644 index 8bd3d36fde..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/MarkModel.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.agileburo.anytype.feature_editor.data - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 03.04.2019. - */ -data class MarkModel(val type: String = "", - val start: Int = 0, - val end: Int = 0, - val param: String = "") \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/converter/BlockTypeConverter.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/converter/BlockTypeConverter.kt deleted file mode 100644 index fa0790a764..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/converter/BlockTypeConverter.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.agileburo.anytype.feature_editor.data.converter - -import com.agileburo.anytype.feature_editor.domain.BlockType -import com.agileburo.anytype.feature_editor.domain.BlockTypes - -fun Int.toBlockType(): BlockType = - when (this) { - BlockTypes.HORIZONTAL_GRID -> BlockType.HrGrid - BlockTypes.VERTICAL_GRID -> BlockType.VrGrid - BlockTypes.EDITABLE -> BlockType.Editable - BlockTypes.DIVIDER -> BlockType.Divider - BlockTypes.VIDEO -> BlockType.Video - BlockTypes.IMAGE -> BlockType.Image - BlockTypes.PAGE -> BlockType.Page - BlockTypes.NEW_PAGE -> BlockType.NewPage - BlockTypes.BOOKMARK -> BlockType.BookMark - BlockTypes.FILE -> BlockType.File - else -> throw IllegalStateException("Unexpected block type code: $this") - } - -fun BlockType.toNumericalCode() : Int = - when(this) { - BlockType.HrGrid -> BlockTypes.HORIZONTAL_GRID - BlockType.VrGrid -> BlockTypes.VERTICAL_GRID - BlockType.Editable -> BlockTypes.EDITABLE - BlockType.Divider -> BlockTypes.DIVIDER - BlockType.Video -> BlockTypes.VIDEO - BlockType.Image -> BlockTypes.IMAGE - BlockType.Page -> BlockTypes.PAGE - BlockType.NewPage -> BlockTypes.NEW_PAGE - BlockType.BookMark -> BlockTypes.BOOKMARK - BlockType.File -> BlockTypes.FILE - } diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/converter/ContentTypeConverter.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/converter/ContentTypeConverter.kt deleted file mode 100644 index 147c96877c..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/converter/ContentTypeConverter.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.agileburo.anytype.feature_editor.data.converter - -import com.agileburo.anytype.feature_editor.domain.ContentType -import com.agileburo.anytype.feature_editor.domain.ContentTypes - -fun Int.toContentType(): ContentType = - when (this) { - ContentTypes.UNDEFINED -> ContentType.None - ContentTypes.PARAGRAPH -> ContentType.P - ContentTypes.CODE_SNIPPET -> ContentType.Code - ContentTypes.HEADER_ONE -> ContentType.H1 - ContentTypes.HEADER_TWO -> ContentType.H2 - ContentTypes.HEADER_THREE -> ContentType.H3 - ContentTypes.NUMBERED_LIST -> ContentType.NumberedList - ContentTypes.BULLET_LIST_ITEM -> ContentType.UL - ContentTypes.QUOTE -> ContentType.Quote - ContentTypes.TOGGLE -> ContentType.Toggle - ContentTypes.CHECKBOX -> ContentType.Check - ContentTypes.HEADER_FOUR -> ContentType.H4 - else -> throw IllegalStateException("Unexpected content type code: $this") - } - -fun ContentType.toNumericalCode(): Int = - when (this) { - ContentType.None -> ContentTypes.UNDEFINED - ContentType.P -> ContentTypes.PARAGRAPH - ContentType.Code -> ContentTypes.CODE_SNIPPET - ContentType.H1 -> ContentTypes.HEADER_ONE - ContentType.H2 -> ContentTypes.HEADER_TWO - ContentType.H3 -> ContentTypes.HEADER_THREE - ContentType.NumberedList -> ContentTypes.NUMBERED_LIST - ContentType.UL -> ContentTypes.BULLET_LIST_ITEM - ContentType.Quote -> ContentTypes.QUOTE - ContentType.Toggle -> ContentTypes.TOGGLE - ContentType.Check -> ContentTypes.CHECKBOX - ContentType.H4 -> ContentTypes.HEADER_FOUR - } diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/datasource/BlockDataSource.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/datasource/BlockDataSource.kt deleted file mode 100644 index c326fa0eb2..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/datasource/BlockDataSource.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.agileburo.anytype.feature_editor.data.datasource - -import android.content.Context -import com.agileburo.anytype.feature_editor.BuildConfig -import com.agileburo.anytype.feature_editor.data.BlockModel -import com.google.gson.Gson -import io.reactivex.Single -import javax.inject.Inject - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 20.03.2019. - */ -interface BlockDataSource { - fun getBlocks(): Single> -} - -class IPFSDataSourceImpl @Inject constructor( - private val context: Context, - private val gson: Gson -) : BlockDataSource { - - override fun getBlocks(): Single> { - return Single.create> { emitter -> - try { - val json = context.assets.open(BuildConfig.TEST_JSON).bufferedReader().use { - it.readText() - } - - val ipfsResponse = gson.fromJson(json, IpfsResponse::class.java) - - emitter.onSuccess(ipfsResponse.blocks) - - } catch (e: Exception) { - emitter.onError(e) - } - } - } -} - -data class IpfsResponse(val blocks: List = emptyList()) \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/parser/ContentModelParser.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/parser/ContentModelParser.kt deleted file mode 100644 index 295ec2fb63..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/data/parser/ContentModelParser.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.agileburo.anytype.feature_editor.data.parser - -import com.agileburo.anytype.feature_editor.data.ContentModel -import com.agileburo.anytype.feature_editor.domain.BlockType -import com.google.gson.Gson -import com.google.gson.JsonElement - -class ContentModelParser(val gson : Gson) { - - fun parse(json : JsonElement, blockType : BlockType) : ContentModel { - return when(blockType) { - BlockType.Editable -> { - gson.fromJson(json, ContentModel.Text::class.java) - } - BlockType.Page -> { - gson.fromJson(json, ContentModel.Page::class.java) - } - BlockType.BookMark -> { - gson.fromJson(json, ContentModel.Bookmark::class.java) - } - BlockType.Image -> { - gson.fromJson(json, ContentModel.Image::class.java) - } - else -> TODO() - } - } - -} diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/Block.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/Block.kt deleted file mode 100644 index d51acb2670..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/Block.kt +++ /dev/null @@ -1,496 +0,0 @@ -package com.agileburo.anytype.feature_editor.domain - -import com.agileburo.anytype.feature_editor.presentation.mapper.BlockViewMapper -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import java.util.* - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 14.03.2019. - */ -sealed class BlockType { - object HrGrid : BlockType() - object VrGrid : BlockType() - object Editable : BlockType() - object Divider : BlockType() - object Video : BlockType() - object Image : BlockType() - object Page : BlockType() - object NewPage : BlockType() - object BookMark : BlockType() - object File : BlockType() -} - -sealed class ContentType { - object None : ContentType() - object P : ContentType() - object Code : ContentType() - object H1 : ContentType() - object H2 : ContentType() - object H3 : ContentType() - object NumberedList : ContentType() - object UL : ContentType() - object Quote : ContentType() - object Toggle : ContentType() - object Check : ContentType() - object H4 : ContentType() -} - -typealias Document = MutableList - -data class Block( - val id: String, - val parentId: String, - val contentType: ContentType, - val blockType: BlockType, - val content: Content, - val children : MutableList = mutableListOf(), - val state : State = State.expanded(false) -) { - - fun isNumberedList() = contentType == ContentType.NumberedList - - fun setNumber(number: Int) { - if (content is Content.Text) content.param.number = number - } - - fun isConsumer(): Boolean = when (contentType) { - ContentType.Toggle, ContentType.Check, ContentType.NumberedList, ContentType.UL -> true - else -> false - } - - fun hasParent() = parentId.isNotEmpty() - - fun isList() : Boolean { - return when(contentType) { - ContentType.NumberedList, ContentType.UL, ContentType.Check -> true - else -> false - } - } - - fun isCheckbox() = contentType == ContentType.Check - - fun isToggle() = contentType == ContentType.Toggle - - data class State(val map : MutableMap = mutableMapOf()) { - var expanded : Boolean by map - var focused : Boolean by map - - companion object { - fun expanded(expanded : Boolean = false) = State(mutableMapOf("expanded" to expanded, "focused" to false)) - fun focused(focused : Boolean = false) = State(mutableMapOf("focused" to focused)) - } - } - - companion object { - fun new(parentId: String, contentType : ContentType) : Block { - return Block( - id = UUID.randomUUID().toString(), - parentId = parentId, - content = Content.Text( - marks = emptyList(), - text = "", - param = ContentParam.empty() - ), - blockType = BlockType.Editable, - contentType = contentType, - state = State.focused(true) - ) - } - } - -} - -/** - * Flattens document, so that as result we get a flattened list. - * @return list, in which all blocks do not have children (parent-child relations are indicated only via parentId) - */ -fun Document.flat() : List { - val result = mutableListOf() - - forEach { block -> - result.add(block.copy(children = mutableListOf())) - if (block.children.isNotEmpty()) result.addAll(block.children.flat()) - } - - return result -} - -/** - * This method allows to transform a flattened list of block into a graph-like structured document. - */ -fun Document.graph() : Document { - val map = this.associateBy { block -> block.id }.toMutableMap() - - forEach { block -> - if (block.parentId.isNotEmpty()) { - map[block.parentId]?.let { parent -> - parent.children.add(block) - map[block.parentId] = parent - map[block.id] = block - } - } - } - - return map.values.filter { block -> block.parentId.isEmpty() }.toMutableList() -} - -/** - * Search inside a flattened block list. - */ -fun Document.flatSearch(id : String) : Block? { - return flat().find { block -> block.id == id }?.copy() -} - -/** - * Search inside a graph-like structured document. - * @param id id of the block to search - * @return returns a copy instance of the block, or null if it is not present inside the document - */ -fun Document.search(id : String) : Block? { - forEach { block -> - if (block.id == id) return block.copy() - - if (block.children.isNotEmpty()) { - val result = block.children.search(id) - if (result != null) return result.copy() - } - } - - return null -} - -/** - * @param targetId id of the block to update. - * @param targetType new content type for the block that is being updated - */ -@Throws(IllegalStateException::class) -fun Document.changeContentType(targetId : String, targetType: ContentType) { - - search(targetId)?.let { target -> - - if (target.contentType == targetType) return - - if (target.parentId.isNotEmpty()) { - - // Changing content type at children level - - search(target.parentId)?.let { parent -> - - val index = parent.children.indexOf(target) - - parent.children[index] = target.copy(contentType = targetType) - - // treat toggle block children move. - - if (target.contentType == ContentType.Toggle) { - - // move toggle block children to an upper level - - if (target.children.isNotEmpty()) { - - val children = target.children.map { it.copy(parentId = parent.id) } - - // remove children from toggle block - - target.children.clear() - - // add children to their new parent (i.e. parent of the target block) - - if (index < parent.children.size - 1) { - val slice = slice(index + 1 until parent.children.size) - parent.children.removeAll { child -> slice.contains(child) } - parent.children.addAll(children + slice) - } else { - parent.children.addAll(children) - } - } - } - } ?: throw IllegalStateException("Could not found parent by id : ${target.parentId}") - - } else { - - // Changing content type at root level - - val index = indexOf(target) - - set(index, target.copy(contentType = targetType)) - - // treat toggle block children move. - - if (target.contentType == ContentType.Toggle) { - - // move toggle block children to root level - - if (target.children.isNotEmpty()) { - - val children = target.children.map { it.copy(parentId = "") } - - target.children.clear() - - // add children to root revel - - if (index < size - 1) { - val slice = slice(index + 1 until size) - removeAll { slice.contains(it) } - addAll(children + slice) - } else { - addAll(children) - } - } - } - } - - } ?: throw IllegalStateException("Could not find target by id: $targetId") -} - -/** - * Deletes block by id. - * @param targetId id of the block to delete - */ -fun Document.delete(targetId : String) { - val block = search(targetId) - - check(block != null) { "Could not found block with id : $targetId" } - - if (block.parentId.isNotEmpty()) { - val parent = search(block.parentId) - check(parent != null) { "Could not found parent by id: ${block.parentId}" } - parent.children.removeIf { it.id == block.id } - } else { - removeIf { it.id == block.id } - } - -} - -/** - * @param targetId id of the block to update. - * @param targetContentUpdate new content for the block that is being updated. - */ -fun Document.updateContent(targetId : String, targetContentUpdate : Content) { - val current = search(targetId) - if (current != null) { - if (current.parentId.isNotEmpty()) { - val parent = search(current.parentId) - if (parent != null) { - val index = parent.children.indexOf(current) - parent.children[index] = current.copy(content = targetContentUpdate) - } - } else { - val index = indexOfFirst { block -> block.id == targetId } - set(index, current.copy(content = targetContentUpdate)) - } - } -} - -/** - * Fixes number order inside document. - */ -fun Document.fixNumberOrder() { - var number = 0 - - forEach { block -> - if (block.isNumberedList()) { - number++ - block.setNumber(number) - } else { - number = 0 - } - if (block.children.isNotEmpty()) { - block.children.fixNumberOrder() - } - } -} - -/** - * @param indent current indent (starting with 0) - * @return a document representation adapted for rendering. - * - */ -fun Document.toView(indent : Int = 0) : List { - - val mapper = BlockViewMapper() - - val result = mutableListOf() - - forEach { block -> - - result.add(mapper.mapToView(model = block, indent = indent)) - - if (block.isToggle()) { - if (block.children.isNotEmpty() && block.state.expanded) { - result.addAll(block.children.toView(indent.inc())) - } - } else if (block.isList()) { - if (block.children.isNotEmpty()) { - result.addAll(block.children.toView(indent.inc())) - } - } else { - if (block.children.isNotEmpty()) { - result.addAll(block.children.toView(indent)) - } - } - } - - return result -} - -@Throws(IllegalStateException::class) -fun Document.consume(consumerId : String, consumableId : String) { - search(consumerId)?.let { consumer -> - if (consumer.isConsumer()) - search(consumableId)?.let { consumable -> - val parent = search(consumable.parentId) - if (parent != null) { - val index = parent.children.indexOf(consumable) - parent.children.removeAt(index) - consumer.children.add(consumable.copy(parentId = consumer.id)) - } else { - val index = indexOf(consumable) - removeAt(index) - consumer.children.add(consumable.copy(parentId = consumer.id)) - } - } ?: throw IllegalStateException("Could not find consumable with id: $consumableId") - - } ?: throw IllegalStateException("Could not find consumer with id: $consumerId") - -} - -fun Document.moveAfter(previousId : String, targetId : String) { - - search(previousId)?.let { previous -> - - search(targetId)?.let { target -> - - if (previous.hasParent()) { - - search(previous.parentId)?.let { parent -> - - if (target.hasParent() && target.parentId != parent.id) { - search(target.parentId)?.let { targetParent -> - targetParent.children.removeIf { child -> child.id == targetId } - } ?: throw IllegalStateException("Could not found parent for target id: $targetId") - } else { - removeIf { block -> block.id == target.id } - } - - val result = mutableListOf() - - parent.children.forEach { child -> - if (child.id != targetId) - result.add(child) - if (child.id == previousId) - result.add(target.copy(parentId = parent.id)) - } - - parent.children.apply { - clear() - addAll(result) - } - - } ?: throw IllegalStateException("Could not find parent for previous block by parent id: ${previous.parentId}") - - } else { - - if (target.hasParent()) { - - if (target.parentId != previous.parentId) { - search(target.parentId)?.let { targetParent -> - targetParent.children.removeIf { child -> child.id == targetId } - } ?: throw IllegalStateException("Could not found parent for target id: $targetId") - } - - val result = mutableListOf() - - forEach { child -> - result.add(child) - if (child.id == previousId) - result.add(target.copy(parentId = previous.parentId)) - } - - clear() - addAll(result) - - } else { - - val result = mutableListOf() - - forEach { child -> - if (child.id != targetId) - result.add(child) - if (child.id == previousId) - result.add(target.copy(parentId = previous.parentId)) - } - - clear() - addAll(result) - } - } - - } ?: throw IllegalStateException("Could not find target block with id: $targetId") - - } ?: throw IllegalStateException("Could not find previous block with id: $previousId") -} - -/** - * Inserts a new block after given block according to block hierarchy. - * @param previousBlockId id of the previous block (new block is inserted after this block) - */ -fun Document.insertNewBlockAfter(previousBlockId : String) { - - search(previousBlockId)?.let { previous -> - - val newContentType = if (previous.isCheckbox() || previous.isList()) previous.contentType else ContentType.P - - val newBlock = Block.new( - parentId = previous.parentId, - contentType = newContentType - ) - - if (previous.parentId.isNotEmpty()) { - - search(previous.parentId)?.let { parent -> - - val result = mutableListOf() - - parent.children.forEach { block -> - result.add(block) - if (block.id == previousBlockId) result.add(newBlock) - } - - parent.children.apply { - clear() - addAll(result) - } - - } ?: throw IllegalStateException("Could not found parent for previous item with parent id: ${previous.parentId}") - - } else { - - val result = mutableListOf() - - forEach { block -> - result.add(block) - if (block.id == previousBlockId) result.add(newBlock) - } - - this.clear() - this.addAll(result) - } - - - } ?: throw IllegalStateException("Could not found previous block with id: $previousBlockId") -} - -/** - * Applies given action on every block of this document. - * Only a variable field of a block can be modified by this method. - * @param action action on block instance. - */ -fun Document.applyToAll(action : (Block) -> Unit) { - forEach { block -> - action(block) - block.children.applyToAll(action) - } -} diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/BlockTypes.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/BlockTypes.kt deleted file mode 100644 index 6edceb71f7..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/BlockTypes.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.agileburo.anytype.feature_editor.domain - -object BlockTypes { - const val HORIZONTAL_GRID = 1 - const val VERTICAL_GRID = 2 - const val EDITABLE = 3 - const val DIVIDER = 4 - const val VIDEO = 5 - const val IMAGE = 6 - const val PAGE = 7 - const val NEW_PAGE = 8 - const val BOOKMARK = 9 - const val FILE = 10 -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/Content.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/Content.kt deleted file mode 100644 index 69055ed15e..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/Content.kt +++ /dev/null @@ -1,87 +0,0 @@ -package com.agileburo.anytype.feature_editor.domain - -sealed class Content { - - data class Text( - val text : String, - val param : ContentParam, - val marks : List - ) : Content() - - data class Page( - val id : String - ) : Content() - - data class Bookmark( - val type : String, - val url : String, - val title : String, - val description : String, - val site : String, - val icon : String, - val images : List - ) : Content() { - - data class Image(val url : String) - - } - - @Deprecated("Picture will be downloaded from device or in some other way") - data class Picture( - val url : String, - val type : Type - ) : Content() { - enum class Type { ORIGINAL, THUMBNAIL } - } - - object Empty : Content() - - -} - -data class ContentParam(val map : MutableMap) { - var number : Int by map - var checked : Boolean by map - - - companion object { - - fun checkbox(checked : Boolean) : ContentParam { - return ContentParam( - mutableMapOf( - "number" to 0, - "checked" to checked - ) - ) - } - - fun empty() : ContentParam { - return ContentParam( - mutableMapOf( - "number" to 0, - "checked" to false - ) - ) - } - - fun numberedList(number : Int = 1): ContentParam { - return ContentParam( - mutableMapOf( - "number" to number, - "checked" to false - ) - ) - } - } -} - -data class Mark( - val start : Int, - val end : Int, - val type : MarkType, - val param: String -) { - enum class MarkType { - BOLD, ITALIC, UNDERLINE, STRIKE_THROUGH, HYPERTEXT, CODE, UNDEFINED - } -} diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/ContentTypes.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/ContentTypes.kt deleted file mode 100644 index 58521d9247..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/ContentTypes.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.agileburo.anytype.feature_editor.domain - -object ContentTypes { - const val UNDEFINED = 0 - const val PARAGRAPH = 1 - const val CODE_SNIPPET = 2 - const val HEADER_ONE = 3 - const val HEADER_TWO = 4 - const val HEADER_THREE = 5 - const val NUMBERED_LIST = 6 - const val BULLET_LIST_ITEM = 7 - const val QUOTE = 8 - const val TOGGLE = 9 - const val CHECKBOX = 10 - const val HEADER_FOUR = 11 -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/EditorInteractor.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/EditorInteractor.kt deleted file mode 100644 index d8af6edba3..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/domain/EditorInteractor.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.agileburo.anytype.feature_editor.domain - -import com.agileburo.anytype.feature_editor.data.EditorRepo -import io.reactivex.Observable -import io.reactivex.Single -import javax.inject.Inject - -interface EditorInteractor { - - fun getBlocks(): Single> - fun saveState(list: MutableList) -} - -class EditorInteractorImpl @Inject constructor(private val repo: EditorRepo) : EditorInteractor { - - override fun getBlocks(): Single> = - repo.getBlocks() - .flattenAsObservable { blocks -> blocks } - .toList() - - override fun saveState(list: MutableList) { - repo.saveState(list) - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/converter/BlockContentTypeConverter.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/converter/BlockContentTypeConverter.kt deleted file mode 100644 index 91498f0296..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/converter/BlockContentTypeConverter.kt +++ /dev/null @@ -1,140 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.converter - -import com.agileburo.anytype.feature_editor.domain.Block -import com.agileburo.anytype.feature_editor.domain.Content -import com.agileburo.anytype.feature_editor.domain.ContentParam -import com.agileburo.anytype.feature_editor.domain.ContentType - -interface BlockContentTypeConverter { - - /** - * @param block block to convert - * @param type content type for new block - */ - fun convert(block : Block, type : ContentType) : Block - - /** - * @param blocks list of blocks - * @param target block that we need to convert - * @param targetType type for a new block - */ - fun convert(blocks : List, target : Block, targetType : ContentType) : List - - fun normalizeNumbers(blocks : List) : List - - fun getPermittedTypes(typeInitial: ContentType): Set - fun getForbiddenTypes(typeInitial: ContentType): Set -} - -class BlockContentTypeConverterImpl : - BlockContentTypeConverter { - - override - fun getPermittedTypes(typeInitial: ContentType): Set = - setOf( - ContentType.P, ContentType.Code, ContentType.H1, ContentType.H2, - ContentType.H3, ContentType.NumberedList, ContentType.UL, ContentType.Quote, - ContentType.Toggle, ContentType.Check, ContentType.H4, ContentType.None - ) - - //Если вдруг появятся недопустимые варианты для конвертации, добавлять можно здесь - override fun getForbiddenTypes(typeInitial: ContentType): Set = - when (typeInitial) { - //Выключаем H1 при работе с блоком, используем H2, H2, H4 - ContentType.P -> setOf(ContentType.H1) - else -> setOf(ContentType.H1) - } - - override fun convert(block: Block, type: ContentType): Block { - return when (type) { - ContentType.NumberedList -> { - block.copy( - contentType = type, - content = (block.content as Content.Text).copy(param = ContentParam.numberedList()) - ) - } - else -> { - block.copy(contentType = type) - } - } - } - - override fun convert(blocks: List, target: Block, targetType: ContentType): List { - - if (target.contentType == targetType) - return blocks - else - when (targetType) { - - ContentType.NumberedList -> { - - val result = mutableListOf() - - blocks.forEach { block -> - if (block.id == target.id) { - val item = block.copy( - contentType = targetType, - content = (block.content as Content.Text).copy( - param = ContentParam.numberedList() - ) - ) - result.add(item) - } else { - result.add(block) - } - } - - return normalizeNumbers(result) - } - - else -> { - - val result = blocks.toMutableList().also { result -> - val index = blocks.indexOf(target) - val converted = target.copy(contentType = targetType) - result[index] = converted - } - - return normalizeNumbers(result) - - } - } - } - - override fun normalizeNumbers(blocks: List): List { - - if (blocks.isEmpty()) - return emptyList() - - val result = mutableListOf() - - var number = 0 - var isPreviousNumbered = false - - blocks.forEach { block -> - if (block.contentType == ContentType.NumberedList) { - - if (isPreviousNumbered) { - number++ - block.setNumber(number) - } else { - number = 1 - block.setNumber(number) - } - - isPreviousNumbered = true - - } else { - block.setNumber(0) - isPreviousNumbered = false - } - - result.add(block) - - } - - return result - - } - -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mapper/BlockModelMapper.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mapper/BlockModelMapper.kt deleted file mode 100644 index e1cd17f1c6..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mapper/BlockModelMapper.kt +++ /dev/null @@ -1,184 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.mapper - -import android.graphics.Typeface -import android.text.SpannableString -import android.text.style.StrikethroughSpan -import android.text.style.StyleSpan -import android.text.style.URLSpan -import com.agileburo.anytype.feature_editor.domain.* -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import com.agileburo.anytype.feature_editor.presentation.model.BlockView.HeaderView.* - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 2019-05-15. - */ - -interface ModelMapper { - fun mapToModel(view: V): D -} - -class BlockModelMapper : ModelMapper { - - override fun mapToModel(view: BlockView): Block { - //todo Разобраться с parentId - - return when (view) { - is BlockView.ParagraphView -> { - Block( - id = view.id, - parentId = "test", - contentType = ContentType.P, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.empty() - ), - blockType = BlockType.Editable - ) - } - is BlockView.QuoteView -> { - Block( - id = view.id, - parentId = "", - contentType = ContentType.Quote, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.empty() - ), - blockType = BlockType.Editable - ) - } - is BlockView.CodeSnippetView -> { - Block( - id = view.id, - parentId = "", - contentType = ContentType.Code, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.empty() - ), - blockType = BlockType.Editable - ) - } - is BlockView.CheckboxView -> { - Block( - id = view.id, - parentId = "", - contentType = ContentType.Check, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.checkbox(view.isChecked) - ), - blockType = BlockType.Editable - ) - } - is BlockView.HeaderView -> { - - val contentType = when(view.type) { - HeaderType.ONE -> ContentType.H1 - HeaderType.TWO -> ContentType.H2 - HeaderType.THREE -> ContentType.H3 - HeaderType.FOUR -> ContentType.H4 - } - - Block( - id = view.id, - parentId = "", - contentType = contentType, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.empty() - ), - blockType = BlockType.Editable - ) - } - - is BlockView.BulletView -> { - Block( - id = view.id, - parentId = "", - contentType = ContentType.UL, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.empty() - ), - blockType = BlockType.Editable - ) - } - is BlockView.NumberListItemView -> { - Block( - id = view.id, - parentId = "", - contentType = ContentType.NumberedList, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.numberedList(view.number) - ), - blockType = BlockType.Editable - ) - } - - is BlockView.ToggleView -> { - Block( - id = view.id, - parentId = "lost", - contentType = ContentType.Toggle, - content = Content.Text( - text = view.text.toString(), - marks = fromSpannableToMarks(view.text), - param = ContentParam.empty() - ), - blockType = BlockType.Editable - ) - } - - else -> TODO() - - } - - - } - - private fun fromSpannableToMarks(content: CharSequence): List { - val text = SpannableString(content) - val marks = ArrayList() - text.getSpans(0, text.length, StyleSpan::class.java).forEach { - val start = text.getSpanStart(it) - val end = text.getSpanEnd(it) - if (start <= end) { - marks.add(Mark(start = start, end = end, param = "", type = getStyleMarkType(it.style))) - } - } - text.getSpans(0, text.length, StrikethroughSpan::class.java).forEach { - val start = text.getSpanStart(it) - val end = text.getSpanEnd(it) - if (start <= end) { - marks.add(Mark(start = start, end = end, param = "", type = Mark.MarkType.STRIKE_THROUGH)) - } - } - text.getSpans(0, text.length, URLSpan::class.java).forEach { - val start = text.getSpanStart(it) - val end = text.getSpanEnd(it) - if (start <= end) { - marks.add(Mark(start = start, end = end, param = it.url, type = Mark.MarkType.HYPERTEXT)) - } - } - return marks - } - - private fun getStyleMarkType(style: Int) = - when (style) { - Typeface.BOLD -> Mark.MarkType.BOLD - Typeface.ITALIC -> Mark.MarkType.ITALIC - else -> Mark.MarkType.UNDEFINED - } -} - diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mapper/BlockViewMapper.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mapper/BlockViewMapper.kt deleted file mode 100644 index 66737fc22c..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mapper/BlockViewMapper.kt +++ /dev/null @@ -1,256 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.mapper - -import android.graphics.Typeface -import android.text.Spannable -import android.text.SpannableString -import android.text.style.ClickableSpan -import android.text.style.StrikethroughSpan -import android.text.style.StyleSpan -import android.text.style.URLSpan -import android.view.View -import com.agileburo.anytype.feature_editor.domain.* -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import com.agileburo.anytype.feature_editor.ui.CodeBlockSpan - -interface ViewMapper { - fun mapToView(model: D, indent : Int = 0): V -} - -class BlockViewMapper : ViewMapper { - - override fun mapToView(model: Block, indent : Int): BlockView { - return when (model.blockType) { - is BlockType.Editable -> { - when (model.contentType) { - is ContentType.P -> { - BlockView.ParagraphView( - indent = indent, - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - focused = model.state.focused - ) - } - is ContentType.H1 -> { - BlockView.HeaderView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - type = BlockView.HeaderView.HeaderType.ONE, - indent = indent, - focused = model.state.focused - ) - } - is ContentType.H2 -> { - BlockView.HeaderView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - type = BlockView.HeaderView.HeaderType.TWO, - indent = indent, - focused = model.state.focused - ) - } - is ContentType.H3 -> { - BlockView.HeaderView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - type = BlockView.HeaderView.HeaderType.THREE, - indent = indent, - focused = model.state.focused - ) - } - is ContentType.H4 -> { - BlockView.HeaderView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - type = BlockView.HeaderView.HeaderType.FOUR, - indent = indent, - focused = model.state.focused - ) - } - is ContentType.Quote -> { - BlockView.QuoteView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - indent = indent, - focused = model.state.focused - ) - } - is ContentType.Code -> { - BlockView.CodeSnippetView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - indent = indent, - focused = model.state.focused - ) - } - is ContentType.Check -> { - BlockView.CheckboxView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - isChecked = model.content.param.checked, - indent = indent, - focused = model.state.focused - ) - } - is ContentType.NumberedList -> { - BlockView.NumberListItemView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - number = model.content.param.number, - indent = indent, - focused = model.state.focused - ) - } - is ContentType.UL -> { - BlockView.BulletView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - indent = indent, - focused = model.state.focused - ) - } - is ContentType.Toggle -> { - BlockView.ToggleView( - id = model.id, - text = fromMarksToSpannable( - marks = (model.content as Content.Text).marks, - text = model.content.text - ), - indent = indent, - expanded = model.state.expanded, - focused = model.state.focused - ) - } - else -> { - throw NotImplementedError("${model.contentType} is not supported") - } - } - } - is BlockType.Page -> { - BlockView.LinkToPageView( - id = model.id, - title = (model.content as Content.Page).id - ) - } - is BlockType.BookMark -> { - BlockView.BookmarkView( - id = model.id, - title = (model.content as Content.Bookmark).title, - description = model.content.description, - url = model.content.url, - image = model.content.images.first().url, - indent = indent - ) - } - is BlockType.Divider -> { - BlockView.DividerView( - id = model.id, - indent = indent - ) - } - is BlockType.Image -> { - BlockView.PictureView( - id = model.id, - url = (model.content as Content.Picture).url, - indent = indent - ) - } - else -> TODO() - } - } - - private fun fromMarksToSpannable(text: String, marks: List) = - SpannableString(text).apply { - marks.forEach { - when (it.type) { - Mark.MarkType.BOLD -> setSpan( - StyleSpan(Typeface.BOLD), - it.start, - it.end, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) - Mark.MarkType.ITALIC -> setSpan( - StyleSpan(Typeface.ITALIC), - it.start, - it.end, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) - Mark.MarkType.STRIKE_THROUGH -> setSpan( - StrikethroughSpan(), - it.start, - it.end, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) - Mark.MarkType.CODE -> setSpan( - CodeBlockSpan(Typeface.DEFAULT), - it.start, - it.end, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) - Mark.MarkType.HYPERTEXT -> { - setSpan(URLSpan(it.param), it.start, it.end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - -//TODO решить задачу EditText + Clickable UrlSpan -// val clickableSpan = object : ClickableSpan() { -// override fun onClick(widget: View?) { -// //onClickListener.invoke() -// Timber.d("On link clicked !!!") -// } -// } -// setSpan(clickableSpan, it.start, it.end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) -// val method = BetterLinkMovementMethod.getInstance() -// textView.movementMethod = method -// textView.setOnTouchListener { _, event -> -// method.onTouchEvent(textView, textView.text as Spannable, event) -// || itemView.onTouchEvent(event) -// } -// withClickableSpan(it.param, it.start.toInt(), it.end.toInt(), click) - } - else -> throw IllegalArgumentException("Not supported type of marks : ${it.type}") - } - } - } - - fun SpannableString.withClickableSpan(clickablePart: String, onClickListener: () -> Unit): SpannableString { - val clickableSpan = object : ClickableSpan() { - override fun onClick(widget: View) = onClickListener.invoke() - } - val clickablePartStart = indexOf(clickablePart) - setSpan( - clickableSpan, - clickablePartStart, - clickablePartStart + clickablePart.length, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE - ) - return this - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/model/BlockView.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/model/BlockView.kt deleted file mode 100644 index ae4c258b51..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/model/BlockView.kt +++ /dev/null @@ -1,111 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.model - -import android.text.SpannableString - -sealed class BlockView { - - abstract val id : String - var isSelected: Boolean = false - - data class ParagraphView( - override val id : String, - override val indent : Int = 0, - override var text : SpannableString, - override val focused: Boolean - ) : BlockView(), Editable, Indentable, Focusable - - data class HeaderView( - override val id : String, - override var text : SpannableString, - val type : HeaderType, - override val indent: Int = 0, - override val focused: Boolean - ) : BlockView(), Editable, Indentable, Focusable { - enum class HeaderType { ONE, TWO, THREE, FOUR } - } - - data class QuoteView( - override val id : String, - override var text : SpannableString, - override val indent : Int = 0, - override val focused: Boolean - ) : BlockView(), Editable, Indentable, Focusable - - data class CheckboxView( - override val id : String, - override var text : SpannableString, - override val indent: Int = 0, - override val focused: Boolean, - val isChecked : Boolean - ) : BlockView(), Editable, Indentable, Focusable - - data class CodeSnippetView( - override val id : String, - override var text : SpannableString, - override val indent : Int = 0, - override val focused: Boolean - ) : BlockView(), Editable, Indentable, Focusable - - data class NumberListItemView( - override val id : String, - override var text: SpannableString, - override val indent : Int = 0, - override val focused: Boolean, - val number : Int - ) : BlockView(), Editable, Indentable, Focusable - - data class BulletView( - override val id : String, - override var text: SpannableString, - override val indent : Int = 0, - override val focused: Boolean - ) : BlockView(), Editable, Indentable, Focusable - - data class LinkToPageView( - override val id : String, - val title : String, - override val indent : Int = 0 - ) : BlockView(), Indentable - - data class BookmarkView( - override val id : String, - val title : String, - val description : String, - val url : String, - val image : String, - override val indent : Int = 0 - ) : BlockView(), Indentable - - data class DividerView( - override val id : String, - override val indent : Int = 0 - ) : BlockView(), Indentable - - data class PictureView ( - override val id : String, - val url : String, - override val indent : Int = 0 - ) : BlockView(), Indentable - - data class ToggleView( - override val id : String, - override val indent : Int = 0, - override var text : SpannableString, - val expanded : Boolean = false, - override val focused: Boolean - ) : BlockView(), Editable, Indentable, Focusable - - interface Editable { - var text : SpannableString - } - - interface Indentable { - val indent : Int - } - - interface Focusable { - val focused : Boolean - } - - interface Consumer -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mvvm/EditorViewModel.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mvvm/EditorViewModel.kt deleted file mode 100644 index f82f2be229..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mvvm/EditorViewModel.kt +++ /dev/null @@ -1,172 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.mvvm - -import androidx.lifecycle.ViewModel -import com.agileburo.anytype.core_utils.ext.BaseSchedulerProvider -import com.agileburo.anytype.core_utils.ext.shift -import com.agileburo.anytype.feature_editor.disposedBy -import com.agileburo.anytype.feature_editor.domain.* -import com.agileburo.anytype.feature_editor.presentation.converter.BlockContentTypeConverter -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import com.agileburo.anytype.feature_editor.presentation.util.DragDropAction -import com.agileburo.anytype.feature_editor.ui.BlockMenuAction -import com.agileburo.anytype.feature_editor.ui.EditorState -import com.jakewharton.rxrelay2.BehaviorRelay -import io.reactivex.disposables.CompositeDisposable -import timber.log.Timber - -class EditorViewModel( - private val interactor: EditorInteractor, - private val contentTypeConverter: BlockContentTypeConverter, - private val schedulerProvider: BaseSchedulerProvider -) : ViewModel() { - - private val subscriptions by lazy { CompositeDisposable() } - private val document : Document by lazy { mutableListOf() } - private val progress by lazy { BehaviorRelay.create() } - - private var positionInFocus: Int = -1 - - init { - fetchBlocks() - } - - fun observeState() = progress - - fun onBlockContentChanged(block: Block) { - document.updateContent( - targetId = block.id, - targetContentUpdate = block.content - ) - } - - fun onExpandClicked(view : BlockView) { - check(view is BlockView.ToggleView) - - document.flatSearch(view.id)?.let { block -> - block.state.expanded = !view.expanded - dispatchBlocksToView() - } - } - - fun onBlockMenuAction(action: BlockMenuAction) { - when (action) { - is BlockMenuAction.ContentTypeAction -> { - document.changeContentType(targetId = action.id, targetType = action.newType) - document.fixNumberOrder() - dispatchBlocksToView() - } - is BlockMenuAction.ArchiveAction -> { - removeBlock(action.id) - } - is BlockMenuAction.DuplicateAction -> { - TODO() - } - } - } - - fun onBlockDragAndDropAction(action: DragDropAction) = when (action) { - is DragDropAction.Shift -> onShiftAction(from = action.from, to = action.to) - is DragDropAction.Consume -> onConsumeAction(target = action.target, consumer = action.consumer) - } - - private fun onShiftAction(from: Int, to: Int) { - val newBlocks = document.shift(from, to) - document.clear() - document.addAll(newBlocks) - dispatchBlocksToView() - normalizeBlocks() - } - - //Todo Update with proper consume action - private fun onConsumeAction(target: Int, consumer: Int) { - document.removeAt(target) - progress.accept(EditorState.Remove(target)) - normalizeBlocks() - } - - fun onConsumeRequested(consumerId : String, consumableId : String) { - document.apply { - consume(consumerId = consumerId, consumableId = consumableId) - fixNumberOrder() - } - dispatchBlocksToView() - } - - fun onMoveAfter(previousId : String, targetId : String) { - document.apply { - moveAfter(previousId, targetId) - fixNumberOrder() - } - dispatchBlocksToView() - } - - fun onBlockFocus(position: Int) { - if (position == -1) { - positionInFocus = position - clearBlockFocus() - return - } - progress.accept(EditorState.DragDropOff) - positionInFocus = position - } - - fun onEnterClicked(id : String) { - - Timber.d("On enter clicked with id: $id") - - document.apply { - applyToAll { it.state.focused = false } - insertNewBlockAfter(previousBlockId = id) - fixNumberOrder() - } - dispatchBlocksToView() - } - - - private fun normalizeBlocks() { - val normalized = contentTypeConverter.normalizeNumbers(document) - document.clear() - document.addAll(normalized) - dispatchBlocksToView() - } - - private fun clearBlockFocus() = - document.getOrNull(positionInFocus)?.let { - progress.accept(EditorState.DragDropOn) - progress.accept( - EditorState.ClearBlockFocus(positionInFocus, it.contentType) - ) - } - - private fun fetchBlocks() { - interactor.getBlocks() - .observeOn(schedulerProvider.ui()) - .subscribeOn(schedulerProvider.io()) - .subscribe( - { data -> onBlockReceived(data) }, - { error -> Timber.e(error, "Error while fetching document") } - ).disposedBy(subscriptions) - } - - private fun onBlockReceived(items: List) { - document.addAll(items) - progress.accept(EditorState.Result(document)) - } - - private fun removeBlock(id: String) { - document.apply { - delete(id) - fixNumberOrder() - } - dispatchBlocksToView() - } - - private fun dispatchBlocksToView() { - progress.accept(EditorState.Updates(document)) - } - - override fun onCleared() { - subscriptions.clear() - super.onCleared() - } -} diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mvvm/EditorViewModelFactory.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mvvm/EditorViewModelFactory.kt deleted file mode 100644 index efc767ade8..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/mvvm/EditorViewModelFactory.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.mvvm - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.agileburo.anytype.core_utils.ext.BaseSchedulerProvider -import com.agileburo.anytype.feature_editor.domain.EditorInteractor -import com.agileburo.anytype.feature_editor.presentation.converter.BlockContentTypeConverter - -class EditorViewModelFactory( - private val editorInteractor: EditorInteractor, - private val contentTypeConverter: BlockContentTypeConverter, - private val schedulerProvider: BaseSchedulerProvider - -) : ViewModelProvider.Factory { - - @Suppress("UNCHECKED_CAST") - override fun create(modelClass: Class): T = - EditorViewModel( - interactor = editorInteractor, - contentTypeConverter = contentTypeConverter, - schedulerProvider = schedulerProvider - ) as T -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/BlockViewDiffUtil.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/BlockViewDiffUtil.kt deleted file mode 100644 index 7ffa399233..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/BlockViewDiffUtil.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.util - -import androidx.recyclerview.widget.DiffUtil -import com.agileburo.anytype.feature_editor.presentation.model.BlockView - -class BlockViewDiffUtil( - private val old : List, - private val new : List -) : DiffUtil.Callback() { - - override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return old[oldItemPosition].id == new[newItemPosition].id - } - - override fun getOldListSize(): Int = old.size - override fun getNewListSize(): Int = new.size - - override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return new[newItemPosition] == old[oldItemPosition] - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/DragDropAction.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/DragDropAction.kt deleted file mode 100644 index b0a8d40b25..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/DragDropAction.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.util - -sealed class DragDropAction { - data class Consume(val target: Int, val consumer: Int) : DragDropAction() - data class Shift(val from: Int, val to: Int) : DragDropAction() -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/SwapRequest.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/SwapRequest.kt deleted file mode 100644 index 172222dda2..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/presentation/util/SwapRequest.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.agileburo.anytype.feature_editor.presentation.util - -data class SwapRequest( - val from : Int, - val to : Int -) \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/BlockMenu.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/BlockMenu.kt deleted file mode 100644 index 57a6808b3d..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/BlockMenu.kt +++ /dev/null @@ -1,127 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.content.Context -import android.view.LayoutInflater -import android.view.View -import android.widget.ImageView -import android.widget.PopupWindow -import com.agileburo.anytype.feature_editor.R -import com.agileburo.anytype.feature_editor.domain.ContentType -import com.agileburo.anytype.feature_editor.presentation.model.BlockView - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 2019-05-20. - */ - - -sealed class BlockMenuAction{ - data class ContentTypeAction(val id : String, val newType: ContentType): BlockMenuAction() - data class ArchiveAction(val id : String): BlockMenuAction() - data class DuplicateAction(val id: String): BlockMenuAction() -} - -const val UNDEFINED_BUTTON = -1 - -class BlockMenu( - private val context: Context, - private val block: BlockView, - private val menuItemClick: (BlockMenuAction) -> Unit -) : PopupWindow(context) { - - init { - setupView() - } - - private fun setupView() { - val view = LayoutInflater.from(context).inflate(getLayout(block), null) - view.findViewById(getButton(block))?.isSelected = true - isOutsideTouchable = true - isFocusable = true - contentView = view - setClicks() - } - - private fun setClicks() { - contentView.findViewById(R.id.btn_menu_p)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.P)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_h2)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.H2)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_h3)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.H3)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_h4)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.H4)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_bullet)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.UL)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_quote)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.Quote)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_numbered)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.NumberedList)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_checkbox)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.Check)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_code)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.Code)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_archive)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ArchiveAction(block.id)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_duplicate)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.DuplicateAction(block.id)) - dismiss() - } - contentView.findViewById(R.id.btn_menu_toggle)?.setOnClickListener { - menuItemClick.invoke(BlockMenuAction.ContentTypeAction(block.id, ContentType.Toggle)) - dismiss() - } - } - - private fun getLayout(block: BlockView): Int = - when (block) { - is BlockView.Editable -> R.layout.popup_edit_block - else -> R.layout.popup_non_edit_block - } - - private fun getButton(block: BlockView) = - when (block) { - is BlockView.ParagraphView -> R.id.btn_menu_p - is BlockView.HeaderView -> { - when (block.type) { - BlockView.HeaderView.HeaderType.ONE -> UNDEFINED_BUTTON - BlockView.HeaderView.HeaderType.TWO -> R.id.btn_menu_h2 - BlockView.HeaderView.HeaderType.THREE -> R.id.btn_menu_h3 - BlockView.HeaderView.HeaderType.FOUR -> R.id.btn_menu_h4 - } - } - is BlockView.BulletView -> R.id.btn_menu_bullet - is BlockView.QuoteView -> R.id.btn_menu_quote - is BlockView.NumberListItemView -> R.id.btn_menu_numbered - is BlockView.CheckboxView -> R.id.btn_menu_checkbox - is BlockView.CodeSnippetView -> R.id.btn_menu_code - is BlockView.ToggleView -> R.id.btn_menu_toggle - - //Todo implement! - is BlockView.LinkToPageView -> throw NotImplementedError() - is BlockView.BookmarkView -> throw NotImplementedError() - is BlockView.DividerView -> throw NotImplementedError() - is BlockView.PictureView -> throw NotImplementedError() - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/ClearFocusEditText.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/ClearFocusEditText.kt deleted file mode 100644 index 69f10a11b0..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/ClearFocusEditText.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.content.Context -import android.util.AttributeSet -import android.view.KeyEvent -import androidx.appcompat.widget.AppCompatEditText - -class ClearFocusEditText : AppCompatEditText { - constructor(context: Context) : super(context) - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super( - context, - attrs, - defStyle - ) - - override fun onKeyPreIme(keyCode: Int, event: KeyEvent?): Boolean { - if (keyCode == KeyEvent.KEYCODE_BACK) { - clearFocus() - } - return super.onKeyPreIme(keyCode, event) - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/CodeBlockSpan.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/CodeBlockSpan.kt deleted file mode 100644 index 736eaf185b..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/CodeBlockSpan.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.graphics.Color -import android.graphics.Typeface -import androidx.annotation.ColorInt -import android.text.TextPaint -import com.agileburo.anytype.feature_editor.ui.FontSpan - -class CodeBlockSpan( - font: Typeface?, - @param:ColorInt private val backgroundColor: Int = Color.LTGRAY -) : FontSpan(font) { - - // Since we're only changing the background color, it will not affect the measure state, so - // just override the updateContent draw state. - override fun updateDrawState(textPaint: TextPaint) { - super.updateDrawState(textPaint) - textPaint.bgColor = backgroundColor - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/DragAndDropBehavior.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/DragAndDropBehavior.kt deleted file mode 100644 index 122fbe4726..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/DragAndDropBehavior.kt +++ /dev/null @@ -1,349 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.graphics.Canvas -import android.graphics.Color -import android.view.View -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.ItemTouchHelper.* -import androidx.recyclerview.widget.RecyclerView -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import com.agileburo.anytype.feature_editor.presentation.util.DragDropAction -import com.jakewharton.rxrelay2.BehaviorRelay -import io.reactivex.disposables.CompositeDisposable -import kotlin.math.abs - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 2019-08-01. - */ - -interface ItemTouchHelperViewHolder { - - fun targetView() - fun targetViewBottom() - fun clearTargetView() -} - -sealed class DragState { - - /** Send Shift action. */ - data class Shift(val from: RecyclerView.ViewHolder) : DragState() - - /** The opportunity to produce Shift action. Remember shiftView for the future. Render view. */ - data class ShiftRequest(val from: RecyclerView.ViewHolder, val to: RecyclerView.ViewHolder) : DragState() - - /** Delete shiftView */ - object DeleteShiftRequest : DragState() - - /** Send Consume action. */ - data class Consume(val target: RecyclerView.ViewHolder) : DragState() - - /** The opportunity to produce Consume action. Remember consumerView for the future. */ - data class ConsumeRequest(val target: Int, val consumerViewHolder: RecyclerView.ViewHolder?) : DragState() - - /** The user drag element. */ - data class Dragging(val target: Int) : DragState() - - /** The element is not controlled by user and simply animating back to its original state. */ - data class DraggingNotActive(val view: View, val alpha: Float) : DragState() - - /** The user interaction with an element is over and it also completed its animation. */ - object Idle : DragState() -} - -const val CONSUME_INTERVAL = 7 -const val DRAG_STATE_ALPHA = 0.3f -const val CONSUME_STATE_ALPHA = 0.0f -const val IDLE_STATE_ALPHA = 1.0f -const val POSITION_NONE = -1 - -class DragAndDropBehavior( - private val onDragDropAction: (DragDropAction) -> Unit -) : ItemTouchHelper.Callback() { - - private val disposable = CompositeDisposable() - private val subject: BehaviorRelay = BehaviorRelay.createDefault(DragState.Idle) - private var shiftView: RecyclerView.ViewHolder? = null - private var consumerPosition: Int = POSITION_NONE - - fun init() = disposable.addAll(subject.subscribe { handleState(it) }) - fun destroy() = disposable.clear() - - override fun onSwiped(p0: RecyclerView.ViewHolder, p1: Int) {} - override fun getMovementFlags(p0: RecyclerView, p1: RecyclerView.ViewHolder): Int = - makeMovementFlags(UP or DOWN, 0) - - /** - * The user has removed the finger from the screen. - * Check for null viewHolders for Shift or Consume behavior. - * First check for consume action - */ - override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) { - super.clearView(recyclerView, viewHolder) - removeDraggableViewProperties(viewHolder.itemView) - if (consumerPosition > POSITION_NONE) { - subject.accept(DragState.Consume(target = viewHolder)) - return - } - if (shiftView != null) { - subject.accept(DragState.Shift(from = viewHolder)) - return - } - } - - /** - * Returns the fraction that the user should move the View to be considered as it is - * dragged. After a view is moved this amount, ItemTouchHelper starts checking for Views - * below it for a possible drop. - * - * @param viewHolder The ViewHolder that is being dragged. - * @return A float value that denotes the fraction of the View size. Dragging value is - * .5f . - */ - override fun getMoveThreshold(viewHolder: RecyclerView.ViewHolder): Float = 0.1f - - override fun getAnimationDuration( - recyclerView: RecyclerView, - animationType: Int, - animateDx: Float, - animateDy: Float - ): Long = 0 - - override fun isLongPressDragEnabled(): Boolean = true - override fun isItemViewSwipeEnabled(): Boolean = false - - override fun canDropOver( - recyclerView: RecyclerView, - current: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean = target.adapterPosition != 0 - - override fun onMove( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - target: RecyclerView.ViewHolder - ): Boolean { - subject.accept(DragState.ShiftRequest(viewHolder, target)) - return false - } - - override fun onChildDraw( - c: Canvas, - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - dX: Float, - dY: Float, - actionState: Int, - isCurrentlyActive: Boolean - ) { - when (actionState) { - ACTION_STATE_DRAG -> isCurrentlyActive( - recyclerView = recyclerView, dY = dY, - viewHolder = viewHolder, isCurrentlyActive = isCurrentlyActive - ) - else -> Unit - } - super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive) - } - - override fun chooseDropTarget( - selected: RecyclerView.ViewHolder, - dropTargets: MutableList, - curX: Int, - curY: Int - ): RecyclerView.ViewHolder? { - var winner: RecyclerView.ViewHolder? = null - var winnerScore = Int.MAX_VALUE - val dy = curY - selected.itemView.top - dropTargets.forEach { dropTarget -> - with(dropTarget) { - if (this is BlockView.Consumer) { - val selectedTargetCenter = getSelectedTargetCenter(curY, selected.itemView.height) - when { - dy < 0 -> { - val diff = getConsumeTopBorder(itemView.top, itemView.bottom) - selectedTargetCenter - if (diff > 0 && abs(diff) < winnerScore) { - winnerScore = abs(diff) - winner = this - } - } - dy > 0 -> { - val diff = getConsumeBottomBorder(itemView.top, itemView.bottom) - selectedTargetCenter - if (diff < 0 && abs(diff) < winnerScore) { - winnerScore = abs(diff) - winner = this - } - } - else -> Unit - } - } else { - val diff = getDropTargetCenter(itemView.top, itemView.bottom) - - getSelectedTargetCenter(curY, selected.itemView.height) - when { - dy < 0 -> - if (diff > 0 && abs(diff) < winnerScore) { - winnerScore = abs(diff) - winner = this - } else Unit - dy > 0 -> - if (diff < 0 && abs(diff) < winnerScore) { - winnerScore = abs(diff) - winner = this - } else Unit - else -> Unit - } - } - } - } - if (winner == null) { - subject.accept(DragState.DeleteShiftRequest) - } - return winner - } - - private fun setDraggableViewProperties(itemView: View) = with(itemView) { - setBackgroundColor(Color.LTGRAY) - alpha = DRAG_STATE_ALPHA - } - - private fun removeDraggableViewProperties(itemView: View) = with(itemView) { - setBackgroundColor(0) - alpha = IDLE_STATE_ALPHA - } - - private fun isCurrentlyActive( - isCurrentlyActive: Boolean, - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - dY: Float - ) = when (isCurrentlyActive) { - true -> itemDraggedActive(recyclerView, viewHolder, dY) - false -> subject.accept(DragState.DraggingNotActive(viewHolder.itemView, IDLE_STATE_ALPHA)) - } - - private fun itemDraggedActive( - recyclerView: RecyclerView, - viewHolder: RecyclerView.ViewHolder, - dY: Float - ) = with(viewHolder.itemView) { - if (alpha != DRAG_STATE_ALPHA) setDraggableViewProperties(this) - for (x in 0 until recyclerView.childCount) { - val child = recyclerView.getChildAt(x) - if (child != this) { - val consumeCenter = (child.top + child.bottom).div(2) - val interval = child.height.div(CONSUME_INTERVAL) - if (isDraggedItemCanBeConsumeByCenterOfDragged( - consumerCenter = consumeCenter, - interval = interval, - baselineY = getDraggedItemBaseline(this, dY).toInt() - ) - ) { - subject.accept(DragState.DeleteShiftRequest) - val consume = recyclerView.findContainingViewHolder(child) - subject.accept(DragState.ConsumeRequest(viewHolder.adapterPosition, consume)) - break - } else { - if (consumerPosition > POSITION_NONE) { - recyclerView.findViewHolderForAdapterPosition(consumerPosition)?.itemView?.setBackgroundColor(0) - } - subject.accept(DragState.Dragging(viewHolder.adapterPosition)) - } - } - } - } - - private fun handleState(state: DragState) = when (state) { - - is DragState.Shift -> { - shiftView?.let { - consumerPosition = POSITION_NONE - (it as? ItemTouchHelperViewHolder)?.clearTargetView() - onDragDropAction.invoke( - DragDropAction.Shift(from = state.from.adapterPosition, to = it.adapterPosition) - ) - } - shiftView = null - } - - is DragState.ShiftRequest -> { - (shiftView as? ItemTouchHelperViewHolder)?.clearTargetView() - shiftView = null - - if (state.from.adapterPosition > state.to.adapterPosition) { - (state.to as? ItemTouchHelperViewHolder)?.targetView() - } else { - (state.to as? ItemTouchHelperViewHolder)?.targetViewBottom() - } - shiftView = state.to - } - - is DragState.DeleteShiftRequest -> { - (shiftView as? ItemTouchHelperViewHolder)?.clearTargetView() - shiftView = null - } - - is DragState.ConsumeRequest -> { - subject.accept(DragState.DeleteShiftRequest) - state.consumerViewHolder?.let { holder -> - if (holder is BlockView.Consumer) { - holder.itemView.setBackgroundColor(Color.GRAY) - consumerPosition = holder.adapterPosition - } - } - } - - is DragState.Consume -> { - shiftView = null - subject.accept( - DragState.DraggingNotActive(view = state.target.itemView, alpha = CONSUME_STATE_ALPHA) - ) - onDragDropAction.invoke( - DragDropAction.Consume(target = state.target.adapterPosition, consumer = consumerPosition) - ) - } - - is DragState.Dragging -> { - /** shiftView не нужно обнулять, так как после DragState.ShiftRequest может - быть DragState.Dragging и тогда в clearView не случится SwapRequest - */ - consumerPosition = POSITION_NONE - } - - is DragState.DraggingNotActive -> { - if (state.alpha < IDLE_STATE_ALPHA) { - state.view.alpha = state.alpha - } else Unit - } - - is DragState.Idle -> { - subject.accept(DragState.DeleteShiftRequest) - consumerPosition = POSITION_NONE - } - } - - private fun getDraggedItemBaseline(draggedView: View, dY: Float): Float = - (draggedView.top + dY + (draggedView.height / 2)) - - private fun isDraggedItemCanBeConsumeByCenterOfDragged( - consumerCenter: Int, - baselineY: Int, - interval: Int - ): Boolean = baselineY in consumerCenter.minus(interval)..consumerCenter.plus(interval) -} - -fun getDropTargetCenter(top: Int, bottom: Int) = (top + bottom) / 2 - -fun getConsumeTopBorder(top: Int, bottom: Int): Int { - val centerY = getDropTargetCenter(top = top, bottom = bottom) - val height = bottom - top - return centerY - height.div(CONSUME_INTERVAL) -} - -fun getConsumeBottomBorder(top: Int, bottom: Int): Int { - val centerY = getDropTargetCenter(top = top, bottom = bottom) - val height = bottom - top - return centerY + height.div(CONSUME_INTERVAL) -} - -fun getSelectedTargetCenter(curY: Int, height: Int): Int = curY + height.div(2) \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorAdapter.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorAdapter.kt deleted file mode 100644 index 757ffe9c27..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorAdapter.kt +++ /dev/null @@ -1,1263 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.content.Context -import android.graphics.Color -import android.text.* -import android.text.Editable -import android.view.* -import android.view.inputmethod.EditorInfo -import android.widget.EditText -import android.widget.TextView -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView -import com.agileburo.anytype.core_utils.ext.showKeyboard -import com.agileburo.anytype.core_utils.ext.swap -import com.agileburo.anytype.feature_editor.R -import com.agileburo.anytype.feature_editor.presentation.model.BlockView -import com.agileburo.anytype.feature_editor.presentation.model.BlockView.* -import com.agileburo.anytype.feature_editor.presentation.model.BlockView.HeaderView.HeaderType -import com.agileburo.anytype.feature_editor.presentation.util.BlockViewDiffUtil -import com.agileburo.anytype.feature_editor.presentation.util.SwapRequest -import com.bumptech.glide.Glide -import kotlinx.android.synthetic.main.item_block_bookmark.view.* -import kotlinx.android.synthetic.main.item_block_bullet.view.* -import kotlinx.android.synthetic.main.item_block_checkbox.view.* -import kotlinx.android.synthetic.main.item_block_code_snippet.view.* -import kotlinx.android.synthetic.main.item_block_editable.view.* -import kotlinx.android.synthetic.main.item_block_editable.view.textEditable -import kotlinx.android.synthetic.main.item_block_header_four.view.* -import kotlinx.android.synthetic.main.item_block_header_one.view.* -import kotlinx.android.synthetic.main.item_block_header_three.view.* -import kotlinx.android.synthetic.main.item_block_header_two.view.* -import kotlinx.android.synthetic.main.item_block_image.view.* -import kotlinx.android.synthetic.main.item_block_quote.view.* -import kotlinx.android.synthetic.main.item_block_toggle.view.* -import kotlinx.android.synthetic.main.item_number_list_item.view.* - -class EditorAdapter( - val blocks: MutableList, - private val blockContentListener: (BlockView) -> Unit, - private val menuListener: (BlockMenuAction) -> Unit, - private val focusListener: (Int) -> Unit, - private val onExpandClick: (BlockView) -> Unit, - private val onEnterPressed: (String) -> Unit -) : RecyclerView.Adapter() { - - fun setBlocks(items: List) { - blocks.addAll(items) - notifyDataSetChanged() - } - - fun clearSelected() { - blocks.forEach { it.isSelected = false } - notifyDataSetChanged() - } - - fun updateBlock(block: BlockView) { - val index = blocks.indexOfFirst { it.id == block.id } - if (index >= 0 && index < blocks.size) { - blocks[index] = block - notifyItemChanged(index) - } - } - - fun update(items: List) { - val callback = BlockViewDiffUtil(old = blocks, new = items) - val result = DiffUtil.calculateDiff(callback) - blocks.clear() - blocks.addAll(items) - result.dispatchUpdatesTo(this) - } - - // Bug workaround for losing text selection ability, see: - // https://code.google.com/p/android/issues/detail?id=208169 - override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) { - super.onViewAttachedToWindow(holder) - when (holder) { - is ViewHolder.ParagraphHolder -> setIsEnabled(holder.itemView.textEditable) - is ViewHolder.HeaderOneHolder -> setIsEnabled(holder.itemView.textHeaderOne) - is ViewHolder.HeaderTwoHolder -> setIsEnabled(holder.itemView.textHeaderTwo) - is ViewHolder.HeaderThreeHolder -> setIsEnabled(holder.itemView.textHeaderThree) - is ViewHolder.HeaderFourHolder -> setIsEnabled(holder.itemView.textHeaderFour) - is ViewHolder.QuoteHolder -> setIsEnabled(holder.itemView.textQuote) - is ViewHolder.CheckBoxHolder -> setIsEnabled(holder.itemView.textCheckBox) - is ViewHolder.CodeSnippetHolder -> setIsEnabled(holder.itemView.textCode) - is ViewHolder.BulletHolder -> setIsEnabled(holder.itemView.textBullet) - is ViewHolder.NumberedHolder -> setIsEnabled(holder.itemView.contentText) - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - val inflater = LayoutInflater.from(parent.context) - return when (viewType) { - HOLDER_PARAGRAPH -> { - val view = inflater.inflate(R.layout.item_block_editable, parent, false) - ViewHolder.ParagraphHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_HEADER_ONE -> { - val view = inflater.inflate(R.layout.item_block_header_one, parent, false) - ViewHolder.HeaderOneHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_HEADER_TWO -> { - val view = inflater.inflate(R.layout.item_block_header_two, parent, false) - ViewHolder.HeaderTwoHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_HEADER_THREE -> { - val view = inflater.inflate(R.layout.item_block_header_three, parent, false) - ViewHolder.HeaderThreeHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_HEADER_FOUR -> { - val view = inflater.inflate(R.layout.item_block_header_four, parent, false) - ViewHolder.HeaderFourHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_QUOTE -> { - val view = inflater.inflate(R.layout.item_block_quote, parent, false) - ViewHolder.QuoteHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_CHECKBOX -> { - val view = inflater.inflate(R.layout.item_block_checkbox, parent, false) - ViewHolder.CheckBoxHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_CODE_SNIPPET -> { - val view = inflater.inflate(R.layout.item_block_code_snippet, parent, false) - ViewHolder.CodeSnippetHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_BULLET -> { - val view = inflater.inflate(R.layout.item_block_bullet, parent, false) - ViewHolder.BulletHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_NUMBERED -> { - val view = inflater.inflate(R.layout.item_number_list_item, parent, false) - ViewHolder.NumberedHolder(view, MyEditorTextWatcher(blockContentListener)) - } - HOLDER_PAGE -> { - val view = inflater.inflate(R.layout.item_block_link_to_page, parent, false) - ViewHolder.LinkToPageHolder(view) - } - HOLDER_BOOKMARK -> { - val view = inflater.inflate(R.layout.item_block_bookmark, parent, false) - ViewHolder.BookmarkHolder(view) - } - HOLDER_DIVIDER -> { - val view = inflater.inflate(R.layout.item_block_divider, parent, false) - ViewHolder.DividerHolder(view) - } - HOLDER_PICTURE -> { - val view = inflater.inflate(R.layout.item_block_image, parent, false) - ViewHolder.PictureHolder(view) - } - HOLDER_TOGGLE -> { - val view = inflater.inflate(R.layout.item_block_toggle, parent, false) - ViewHolder.ToggleHolder( - itemView = view, - editTextWatcher = MyEditorTextWatcher(blockContentListener) - ) - } - else -> throw IllegalStateException("Unknown toView type: $viewType") - } - } - - override fun getItemViewType(position: Int): Int { - - val block = blocks[position] - - - return when (block) { - is BookmarkView -> HOLDER_BOOKMARK - is LinkToPageView -> HOLDER_PAGE - is ParagraphView -> HOLDER_PARAGRAPH - is QuoteView -> HOLDER_QUOTE - is CodeSnippetView -> HOLDER_CODE_SNIPPET - is CheckboxView -> HOLDER_CHECKBOX - is NumberListItemView -> HOLDER_NUMBERED - is BulletView -> HOLDER_BULLET - is HeaderView -> { - when (block.type) { - HeaderType.ONE -> HOLDER_HEADER_ONE - HeaderType.TWO -> HOLDER_HEADER_TWO - HeaderType.THREE -> HOLDER_HEADER_THREE - HeaderType.FOUR -> HOLDER_HEADER_FOUR - } - } - is DividerView -> HOLDER_DIVIDER - is PictureView -> HOLDER_PICTURE - is ToggleView -> HOLDER_TOGGLE - } - - } - - override fun getItemCount() = blocks.size - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - when (holder) { - is ViewHolder.ParagraphHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.HeaderOneHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.HeaderTwoHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.HeaderThreeHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.HeaderFourHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.QuoteHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.CheckBoxHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.CodeSnippetHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.BulletHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.NumberedHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - block = blocks[position], - menuListener = menuListener, - focusListener = focusListener, - onEnterPressed = onEnterPressed - ) - } - is ViewHolder.BookmarkHolder -> { - holder.bind(blocks[position] as BookmarkView) - } - is ViewHolder.PictureHolder -> { - holder.bind(blocks[position] as PictureView) - } - is ViewHolder.ToggleHolder -> { - holder.editTextWatcher.position = holder.adapterPosition - holder.bind( - view = blocks[position], - onExpandClick = onExpandClick, - menuListener = menuListener, - onEnterPressed = onEnterPressed - ) - } - - } - } - - fun onItemMoved(fromPosition: Int, toPosition: Int): Boolean { - swapPosition(fromPosition, toPosition) - notifyItemMoved(fromPosition, toPosition) - return true - } - - fun swap(request: SwapRequest) { - swapPosition(request.from, request.to) - notifyItemMoved(request.from, request.to) - } - - fun remove(position: Int) { - blocks.removeAt(position) - notifyItemRemoved(position) - } - - private fun swapPosition(fromPosition: Int, toPosition: Int) = - blocks.swap(fromPosition, toPosition) - - private fun setIsEnabled(editText: EditText) { - editText.isEnabled = false - editText.isEnabled = true - } - - sealed class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - - fun select(selected: Boolean) { - if (selected) { - itemView.setBackgroundColor(Color.LTGRAY) - } else { - itemView.setBackgroundColor(0) - } - } - - fun focus(editText: EditText) { - editText.apply { - postDelayed( - { - requestFocus() - showKeyboard() - }, 300 - ) - } - } - - open class IndentableViewHolder(itemView: View) : ViewHolder(itemView) { - - fun applyIndent(indent: Int = 0) { - (itemView.layoutParams as RecyclerView.LayoutParams).apply { - setMargins( - (indent * itemView.context.resources.getDimension(R.dimen.indent).toInt()), - this.topMargin, - this.rightMargin, - this.bottomMargin - ) - } - } - - fun watchEnter( - editText: EditText, - onEnterPressed: (String) -> Unit, - block: BlockView - ) { - - editText.setOnEditorActionListener(null) - - editText.setOnEditorActionListener { _, id, event -> - if (event != null && event.keyCode == KeyEvent.KEYCODE_ENTER) { - onEnterPressed(block.id) - true - } else if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_ACTION_NEXT) { - onEnterPressed(block.id) - false - } else - false - } - } - - } - - class ParagraphHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder { - - private val inputField = itemView.textEditable - private val editButton = itemView.btnEditable - - init { - inputField.textEditable.apply { - addTextChangedListener(editTextWatcher) - //movementMethod = LinkMovementMethod.getInstance() - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is ParagraphView) - - applyIndent(block.indent) - - inputField.apply { - - isLongClickable = false - - customSelectionActionModeCallback = TextStyleCallback(this) { editText, start, end -> - showHyperlinkMenu( - context = itemView.context, - parent = this, - editText = editText, - start = start, - end = end - ) - } - - setText(block.text) - - if (block.focused) focus(this) - - watchEnter(this, onEnterPressed, block) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - - select(isSelected) - } - - override fun targetView() { - itemView.border_top.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.border_bottom.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.border_top.visibility = View.INVISIBLE - itemView.border_bottom.visibility = View.INVISIBLE - } - } - - class HeaderOneHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView) { - - private val inputField = itemView.textHeaderOne - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is HeaderView) - - applyIndent(block.indent) - - inputField.apply { - - isLongClickable = false - - setText(block.text) - - watchEnter(this, onEnterPressed, block) - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - } - } - } - - class HeaderTwoHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder { - - private val inputField = itemView.textHeaderTwo - private val editButton = itemView.btnHeaderTwo - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is HeaderView) - - applyIndent(block.indent) - - inputField.apply { - - setText(block.text) - isLongClickable = false - - watchEnter(this, onEnterPressed, block) - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopHeaderTwo.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomHeaderTwo.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopHeaderTwo.visibility = View.INVISIBLE - itemView.borderBottomHeaderTwo.visibility = View.INVISIBLE - } - } - - class HeaderThreeHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder { - - private val inputField = itemView.textHeaderThree - private val editButton = itemView.btnHeaderThree - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is HeaderView) - - applyIndent(block.indent) - - inputField.apply { - - isLongClickable = false - setText(block.text) - - watchEnter(this, onEnterPressed, block) - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopHeaderThree.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomHeaderThree.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopHeaderThree.visibility = View.INVISIBLE - itemView.borderBottomHeaderThree.visibility = View.INVISIBLE - } - } - - class HeaderFourHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder { - - private val inputField = itemView.textHeaderFour - private val editButton = itemView.btnHeaderFour - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is HeaderView) - - applyIndent(block.indent) - - inputField.apply { - - isLongClickable = false - - setText(block.text) - - watchEnter(this, onEnterPressed, block) - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopHeaderFour.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomHeaderFour.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopHeaderFour.visibility = View.INVISIBLE - itemView.borderBottomHeaderFour.visibility = View.INVISIBLE - } - } - - class QuoteHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder { - - private val inputField = itemView.textQuote - private val editButton = itemView.btnQuote - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - //movementMethod = LinkMovementMethod.getInstance() - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is QuoteView) - - applyIndent(indent = block.indent) - - inputField.apply { - - customSelectionActionModeCallback = - TextStyleCallback(this) - { editText, start, end -> - showHyperlinkMenu( - context = itemView.context, - editText = editText, - start = start, - end = end, - parent = this - ) - } - - isLongClickable = false - - setText(block.text) - - watchEnter(this, onEnterPressed, block) - - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopQuote.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomQuote.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopQuote.visibility = View.INVISIBLE - itemView.borderBottomQuote.visibility = View.INVISIBLE - } - } - - class CheckBoxHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder, Consumer { - - private val inputField = itemView.textCheckBox - private val editButton = itemView.btnCheckboxBlock - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - //movementMethod = LinkMovementMethod.getInstance() - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is CheckboxView) - - applyIndent(block.indent) - - inputField.apply { - setText(block.text) - - isLongClickable = false - - customSelectionActionModeCallback = TextStyleCallback(this) { editText, start, end -> - showHyperlinkMenu( - context = itemView.context, - editText = editText, - start = start, - end = end, - parent = this - ) - } - - watchEnter(this, onEnterPressed, block) - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopCheckBox.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomCheckBox.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopCheckBox.visibility = View.INVISIBLE - itemView.borderBottomCheckBox.visibility = View.INVISIBLE - } - } - - class CodeSnippetHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder { - - private val inputField = itemView.textCode - private val editButton = itemView.btnCode - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is CodeSnippetView) - - applyIndent(block.indent) - - inputField.apply { - setText(block.text) - isLongClickable = false - - watchEnter(this, onEnterPressed, block) - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopCode.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomCode.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopCode.visibility = View.INVISIBLE - itemView.borderBottomCode.visibility = View.INVISIBLE - } - } - - class BulletHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder, Consumer { - - private val inputField = itemView.textBullet - private val editButton = itemView.btnBullet - - init { - inputField.apply { - addTextChangedListener(editTextWatcher) - //movementMethod = LinkMovementMethod.getInstance() - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) = with(block) { - - check(block is BulletView) - - applyIndent(block.indent) - - inputField.apply { - isLongClickable = false - - setText( - SpannableString(block.text) - .withBulletSpan(gapWidth = 40, start = 0), TextView.BufferType.SPANNABLE - ) - - watchEnter(this, onEnterPressed, block) - if (block.focused) focus(this) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - - customSelectionActionModeCallback = TextStyleCallback(this) { editText, start, end -> - showHyperlinkMenu( - context = itemView.context, - editText = editText, - start = start, - end = end, - parent = this - ) - } - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopBullet.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomBullet.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopBullet.visibility = View.INVISIBLE - itemView.borderBottomBullet.visibility = View.INVISIBLE - } - } - - class NumberedHolder( - itemView: View, - val editTextWatcher: MyEditorTextWatcher - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder, Consumer { - - private val inputField = itemView.contentText - private val editButton = itemView.editContentButton - - init { - itemView.contentText.apply { - addTextChangedListener(editTextWatcher) - //movementMethod = LinkMovementMethod.getInstance() - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - block: BlockView, - menuListener: (BlockMenuAction) -> Unit, - focusListener: (Int) -> Unit, - onEnterPressed: (String) -> Unit - ) { - - check(block is NumberListItemView) - - applyIndent(block.indent) - - inputField.apply { - - isLongClickable = false - - setText(block.text) - - customSelectionActionModeCallback = TextStyleCallback(this) { editText, start, end -> - showHyperlinkMenu( - context = itemView.context, - editText = editText, - start = start, - end = end, - parent = this - ) - } - - watchEnter(inputField, onEnterPressed, block) - if (block.focused) focus(inputField) - - setFocusListener( - editText = this, - focusListener = focusListener - ) - - } - - itemView.positionText.text = "${block.number}." - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = block, - menuListener = menuListener, - parent = it - ) - } - } - - override fun targetView() { - itemView.borderTopNumbered.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.borderBottomNumbered.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.borderTopNumbered.visibility = View.INVISIBLE - itemView.borderBottomNumbered.visibility = View.INVISIBLE - } - } - - class LinkToPageHolder(itemView: View) : ViewHolder(itemView) - - class ToggleHolder( - val editTextWatcher: MyEditorTextWatcher, - itemView: View - ) : IndentableViewHolder(itemView), ItemTouchHelperViewHolder, Consumer { - - private val inputField = itemView.textEditable - private val editButton = itemView.blockMenuButton - - init { - itemView.textEditable.apply { - addTextChangedListener(editTextWatcher) - imeOptions = EditorInfo.IME_ACTION_NEXT - setRawInputType(InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) - } - } - - fun bind( - view: BlockView, - onExpandClick: (BlockView) -> Unit, - menuListener: (BlockMenuAction) -> Unit, - onEnterPressed: (String) -> Unit - ) { - - check(view is ToggleView) - - applyIndent(view.indent) - - inputField.apply { - - isLongClickable = false - - setText(view.text) - - watchEnter(this, onEnterPressed, view) - if (view.focused) focus(this) - - // TODO add focus listener? - - } - - editButton.setOnClickListener { - showBlockMenu( - context = itemView.context, - block = view, - menuListener = menuListener, - parent = it - ) - } - - itemView.apply { - toggleArrow.rotation = if (view.expanded) 90f else 0f - arrowContainer.setOnClickListener { onExpandClick(view) } - } - - select(itemView.isSelected) - } - - override fun targetView() { - itemView.topBorder.visibility = View.VISIBLE - } - - override fun targetViewBottom() { - itemView.bottomBorder.visibility = View.VISIBLE - } - - override fun clearTargetView() { - itemView.bottomBorder.visibility = View.INVISIBLE - itemView.topBorder.visibility = View.INVISIBLE - } - } - - class DividerHolder(itemView: View) : ViewHolder(itemView) - - class PictureHolder(itemView: View) : ViewHolder(itemView) { - - fun bind(view: PictureView) { - Glide.with(itemView) - .load(view.url) - .fitCenter() - .into(itemView.picture) - } - } - - class BookmarkHolder(itemView: View) : ViewHolder(itemView) { - - fun bind( - view: BookmarkView - ) { - with(itemView) { - title.text = view.title - description.text = view.description - url.text = view.url - - Glide.with(itemView) - .load(view.image) - .centerCrop() - .into(image) - } - } - } - - fun showHyperlinkMenu( - context: Context, - parent: View, - editText: EditText, - start: Int, - end: Int - ) { - val menu = HyperLinkMenu( - context = context, editText = editText, - start = start, end = end - ) - menu.showAtLocation(parent, Gravity.BOTTOM, 0, 0) - } - - fun showBlockMenu( - context: Context, - parent: View, - block: BlockView, - menuListener: (BlockMenuAction) -> Unit - ) { - BlockMenu(context, block) { menuListener.invoke(it) }.apply { - showAtLocation(parent, Gravity.BOTTOM, 0, 0) - } - } - - fun setFocusListener( - editText: EditText, - focusListener: (Int) -> Unit - ) { - editText.setOnFocusChangeListener { view, hasFocus -> - if (hasFocus) { - view.isLongClickable = true - focusListener.invoke(adapterPosition) - } else { - view.isLongClickable = false - focusListener.invoke(-1) - } - } - } - } - - inner class MyEditorTextWatcher(private val contentListener: (BlockView) -> Unit) : - TextWatcher { - - var position = 0 - - override fun afterTextChanged(s: Editable?) {} - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - s?.let { chars -> - val block = blocks[position] - if (block is BlockView.Editable && chars is SpannableStringBuilder) { - block.text = SpannableString.valueOf(chars) - contentListener.invoke(block) - } - } - } - } - - companion object { - const val HOLDER_PARAGRAPH = 0 - const val HOLDER_HEADER_ONE = 1 - const val HOLDER_HEADER_TWO = 2 - const val HOLDER_HEADER_THREE = 3 - const val HOLDER_QUOTE = 4 - const val HOLDER_CHECKBOX = 5 - const val HOLDER_CODE_SNIPPET = 6 - const val HOLDER_NUMBERED = 7 - const val HOLDER_HEADER_FOUR = 8 - const val HOLDER_BULLET = 9 - const val HOLDER_PAGE = 10 - const val HOLDER_BOOKMARK = 11 - const val HOLDER_DIVIDER = 12 - const val HOLDER_PICTURE = 13 - const val HOLDER_TOGGLE = 14 - } -} - diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorContract.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorContract.kt deleted file mode 100644 index d2a9524094..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorContract.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import com.agileburo.anytype.feature_editor.domain.Block -import com.agileburo.anytype.feature_editor.domain.ContentType -import com.agileburo.anytype.feature_editor.presentation.util.SwapRequest - -/** - * Created by Konstantin Ivanov - * email : ki@agileburo.com - * on 21.03.2019. - */ -sealed class EditorAction { - object PressButton : EditorAction() - data class PressBlock(val id: String) : EditorAction() - data class OnBlockFocus(val position: Int) : EditorAction() -} - -sealed class EditBlockAction { - data class TextClick(val block: Block) : EditBlockAction() - data class Header1Click(val block: Block) : EditBlockAction() - data class Header2Click(val block: Block) : EditBlockAction() - data class Header3Click(val block: Block) : EditBlockAction() - data class Header4Click(val block: Block) : EditBlockAction() - data class HighLightClick(val block: Block) : EditBlockAction() - data class BulletClick(val block: Block) : EditBlockAction() - data class NumberedClick(val block: Block) : EditBlockAction() - data class CheckBoxClick(val block: Block) : EditBlockAction() - data class CodeClick(val block: Block) : EditBlockAction() - data class ArchiveBlock(val id: String) : EditBlockAction() -} - -sealed class EditorState { - data class ClearBlockFocus(val position: Int, val contentType: ContentType) : EditorState() - object HideKeyboard : EditorState() - data class Result(val blocks: List) : EditorState() - data class Swap(val request: SwapRequest) : EditorState() - data class Remove(val position: Int) : EditorState() - data class Updates(val blocks: List) : EditorState() - data class Update(val block: Block) : EditorState() - data class Archive(val id: String) : EditorState() - data class Error(val msg: String) : EditorState() - object DragDropOn : EditorState() - object DragDropOff : EditorState() - object Loading : EditorState() -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorFragment.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorFragment.kt deleted file mode 100644 index d13cfb7968..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/EditorFragment.kt +++ /dev/null @@ -1,181 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.content.Context -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.lifecycle.ViewModelProviders -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.LinearLayoutManager -import com.agileburo.anytype.core_utils.ext.UIExtensions -import com.agileburo.anytype.core_utils.ext.toast -import com.agileburo.anytype.feature_editor.R -import com.agileburo.anytype.feature_editor.disposedBy -import com.agileburo.anytype.feature_editor.domain.Block -import com.agileburo.anytype.feature_editor.domain.ContentType -import com.agileburo.anytype.feature_editor.domain.toView -import com.agileburo.anytype.feature_editor.presentation.mapper.BlockModelMapper -import com.agileburo.anytype.feature_editor.presentation.mapper.BlockViewMapper -import com.agileburo.anytype.feature_editor.presentation.mvvm.EditorViewModel -import com.agileburo.anytype.feature_editor.presentation.mvvm.EditorViewModelFactory -import com.agileburo.anytype.feature_editor.presentation.util.DragDropAction -import com.agileburo.anytype.feature_editor.presentation.util.SwapRequest -import io.reactivex.disposables.CompositeDisposable -import kotlinx.android.synthetic.main.fragment_editor.* -import javax.inject.Inject - -abstract class EditorFragment : Fragment() { - - private val mapper by lazy { BlockViewMapper() } - private val viewToModelMapper by lazy { BlockModelMapper() } - - @Inject - lateinit var factory: EditorViewModelFactory - - private val viewModel by lazy { - ViewModelProviders.of(this, factory).get(EditorViewModel::class.java) - } - - private val disposable = CompositeDisposable() - - private val helper : ItemTouchHelper by lazy { - ItemTouchHelper(dragAndDropBehavior) - } - - private val dragAndDropBehavior by lazy { - DragAndDropBehavior( - onDragDropAction = { action -> - if (action is DragDropAction.Consume) - viewModel.onConsumeRequested( - consumerId = blockAdapter.blocks[action.consumer].id, - consumableId = blockAdapter.blocks[action.target].id - ) - else if (action is DragDropAction.Shift) { - if (action.from < action.to) - viewModel.onMoveAfter( - previousId = blockAdapter.blocks[action.to].id, - targetId = blockAdapter.blocks[action.from].id - ) else - viewModel.onMoveAfter( - previousId = blockAdapter.blocks[action.to - 1].id, - targetId = blockAdapter.blocks[action.from].id - ) - } - } - ) - } - - private val blockAdapter by lazy { - EditorAdapter( - blocks = mutableListOf(), - blockContentListener = { viewModel.onBlockContentChanged(viewToModelMapper.mapToModel(it)) }, - menuListener = viewModel::onBlockMenuAction, - focusListener = viewModel::onBlockFocus, - onExpandClick = viewModel::onExpandClicked, - onEnterPressed = viewModel::onEnterClicked - ).also { - helper.attachToRecyclerView(blockList) - } - } - - abstract fun inject() - - override fun onAttach(context: Context) { - inject() - super.onAttach(context) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { - return inflater.inflate(R.layout.fragment_editor, container, false) - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - viewModel.observeState() - .subscribe(this::handleState) - .disposedBy(disposable) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initializeView() - dragAndDropBehavior.init() - } - - private fun initializeView() = with(blockList) { - layoutManager = LinearLayoutManager(requireContext()) - addItemDecoration(SpaceItemDecoration(space = 48, addSpaceBelowLastItem = true)) - adapter = blockAdapter - } - - override fun onDestroyView() { - dragAndDropBehavior.destroy() - disposable.clear() - super.onDestroyView() - } - - private fun handleState(state: EditorState) = when (state) { - is EditorState.Loading -> { - } - is EditorState.Result -> setBlocks(state.blocks) - is EditorState.Update -> updateBlock(state.block) - - is EditorState.Updates -> render(state.blocks) - - is EditorState.Swap -> swap(state.request) - - is EditorState.Remove -> remove(state.position) - - is EditorState.Archive -> { - } - is EditorState.Error -> onError(state.msg) - is EditorState.ClearBlockFocus -> clearBlockFocus(state.position, state.contentType) - is EditorState.HideKeyboard -> UIExtensions.hideSoftKeyBoard(requireActivity(), blockList) - is EditorState.DragDropOn -> helper.attachToRecyclerView(blockList) - is EditorState.DragDropOff -> { - //Todo Потенциально опасное место, см. https://issuetracker.google.com/issues/140447176 - helper.attachToRecyclerView(null) - } - } - - private fun clearBlockFocus(position: Int, contentType: ContentType) { - blockList.layoutManager?.findViewByPosition(position)?.let { - it.findViewById(getEditTextId(contentType))?.clearFocus() - } - } - - private fun getEditTextId(contentType: ContentType) = - when (contentType) { - is ContentType.P -> R.id.textEditable - is ContentType.H1 -> R.id.textHeaderOne - is ContentType.H2 -> R.id.textHeaderTwo - is ContentType.H3 -> R.id.textHeaderThree - is ContentType.H4 -> R.id.textHeaderFour - is ContentType.Quote -> R.id.textQuote - is ContentType.Check -> R.id.textCheckBox - is ContentType.Code -> R.id.textCode - is ContentType.UL -> R.id.textBullet - is ContentType.NumberedList -> R.id.contentText - is ContentType.None -> throw IllegalStateException() - is ContentType.Toggle -> throw UnsupportedOperationException("need implement Toggle") - } - - private fun setBlocks(blocks: List) = - blockAdapter.setBlocks(blocks.toMutableList().toView()) - - private fun updateBlock(block: Block) = blockAdapter.updateBlock(mapper.mapToView(block)) - - private fun render(blocks: List) = blockAdapter.update(blocks.toMutableList().toView()) - - private fun swap(request: SwapRequest) = blockAdapter.swap(request) - - private fun remove(position: Int) = blockAdapter.remove(position) - - private fun onError(msg: CharSequence) = requireContext().toast(msg) -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/FontSpan.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/FontSpan.kt deleted file mode 100644 index 2a252af346..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/FontSpan.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.graphics.Typeface -import android.text.TextPaint -import android.text.style.MetricAffectingSpan - -open class FontSpan(private val font: Typeface?) : MetricAffectingSpan() { - - override fun updateMeasureState(textPaint: TextPaint) = update(textPaint) - - override fun updateDrawState(textPaint: TextPaint) = update(textPaint) - - private fun update(textPaint: TextPaint) { - textPaint.apply { - val old = typeface - val oldStyle = old?.style ?: 0 - - // keep the style set before - val font = Typeface.create(font, oldStyle) - typeface = font - } - } -} \ No newline at end of file diff --git a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/HyperLinkMenu.kt b/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/HyperLinkMenu.kt deleted file mode 100644 index 5b15972d7f..0000000000 --- a/feature_editor/src/main/java/com/agileburo/anytype/feature_editor/ui/HyperLinkMenu.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.agileburo.anytype.feature_editor.ui - -import android.content.Context -import android.text.SpannableStringBuilder -import android.text.style.URLSpan -import android.view.LayoutInflater -import android.widget.Button -import android.widget.EditText -import android.widget.PopupWindow -import com.agileburo.anytype.feature_editor.R - -class HyperLinkMenu( - private val context: Context, - private val editText: EditText, - private val start: Int, private val end: Int -) : PopupWindow(context) { - - init { - setupView() - } - - private fun setupView() { - val view = LayoutInflater.from(context).inflate(R.layout.popup_hyperlink, null) - isFocusable = true - isOutsideTouchable = true - contentView = view - setClicks() - } - - private fun setClicks() { - val edtLink = contentView.findViewById(R.id.edtLink) - contentView.findViewById