diff --git a/app/src/main/java/com/agileburo/anytype/app/AndroidApplication.kt b/app/src/main/java/com/agileburo/anytype/app/AndroidApplication.kt index a35e47acee..0fe38d983d 100644 --- a/app/src/main/java/com/agileburo/anytype/app/AndroidApplication.kt +++ b/app/src/main/java/com/agileburo/anytype/app/AndroidApplication.kt @@ -4,10 +4,7 @@ import android.app.Application import com.agileburo.anytype.BuildConfig import com.agileburo.anytype.core_utils.tools.CrashlyticsTree import com.agileburo.anytype.di.common.ComponentManager -import com.agileburo.anytype.di.main.ContextModule -import com.agileburo.anytype.di.main.DaggerMainComponent -import com.agileburo.anytype.di.main.DataModule -import com.agileburo.anytype.di.main.MainComponent +import com.agileburo.anytype.di.main.* import com.facebook.stetho.Stetho import timber.log.Timber @@ -18,6 +15,8 @@ class AndroidApplication : Application() { .builder() .contextModule(ContextModule(this)) .dataModule(DataModule()) + .configModule(ConfigModule()) + .utilModule(UtilModule()) .build() } diff --git a/app/src/main/java/com/agileburo/anytype/di/feature/PageDI.kt b/app/src/main/java/com/agileburo/anytype/di/feature/PageDI.kt index 305c002b29..223495e782 100644 --- a/app/src/main/java/com/agileburo/anytype/di/feature/PageDI.kt +++ b/app/src/main/java/com/agileburo/anytype/di/feature/PageDI.kt @@ -5,6 +5,7 @@ import com.agileburo.anytype.domain.block.interactor.* import com.agileburo.anytype.domain.block.repo.BlockRepository import com.agileburo.anytype.domain.event.interactor.EventChannel import com.agileburo.anytype.domain.event.interactor.InterceptEvents +import com.agileburo.anytype.domain.misc.UrlBuilder import com.agileburo.anytype.domain.page.ClosePage import com.agileburo.anytype.domain.page.CreatePage import com.agileburo.anytype.domain.page.OpenPage @@ -51,7 +52,8 @@ class PageModule { mergeBlocks: MergeBlocks, splitBlock: SplitBlock, createPage: CreatePage, - documentExternalEventReducer: DocumentExternalEventReducer + documentExternalEventReducer: DocumentExternalEventReducer, + urlBuilder: UrlBuilder ): PageViewModelFactory = PageViewModelFactory( openPage = openPage, closePage = closePage, @@ -69,7 +71,8 @@ class PageModule { removeLinkMark = removeLinkMark, mergeBlocks = mergeBlocks, splitBlock = splitBlock, - documentEventReducer = documentExternalEventReducer + documentEventReducer = documentExternalEventReducer, + urlBuilder = urlBuilder ) @Provides diff --git a/app/src/main/java/com/agileburo/anytype/di/main/ConfigModule.kt b/app/src/main/java/com/agileburo/anytype/di/main/ConfigModule.kt new file mode 100644 index 0000000000..bf424df532 --- /dev/null +++ b/app/src/main/java/com/agileburo/anytype/di/main/ConfigModule.kt @@ -0,0 +1,25 @@ +package com.agileburo.anytype.di.main + +import com.agileburo.anytype.data.auth.repo.config.Configuration +import com.agileburo.anytype.data.auth.repo.config.Configurator +import com.agileburo.anytype.domain.config.Config +import com.agileburo.anytype.middleware.config.DefaultConfigurator +import dagger.Module +import dagger.Provides +import javax.inject.Singleton + +@Module +class ConfigModule { + + @Provides + @Singleton + fun provideApplicationConfig(configurator: Configurator): Config { + return Configuration(configurator).init() + } + + @Provides + @Singleton + fun provideConfigurator(): Configurator { + return DefaultConfigurator() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/agileburo/anytype/di/main/MainComponent.kt b/app/src/main/java/com/agileburo/anytype/di/main/MainComponent.kt index ddd9b28d6a..51c8145763 100644 --- a/app/src/main/java/com/agileburo/anytype/di/main/MainComponent.kt +++ b/app/src/main/java/com/agileburo/anytype/di/main/MainComponent.kt @@ -10,7 +10,9 @@ import javax.inject.Singleton ContextModule::class, DataModule::class, EventModule::class, - ImageModule::class + ImageModule::class, + ConfigModule::class, + UtilModule::class ] ) interface MainComponent { diff --git a/app/src/main/java/com/agileburo/anytype/di/main/UtilModule.kt b/app/src/main/java/com/agileburo/anytype/di/main/UtilModule.kt new file mode 100644 index 0000000000..2a1cd12e3c --- /dev/null +++ b/app/src/main/java/com/agileburo/anytype/di/main/UtilModule.kt @@ -0,0 +1,17 @@ +package com.agileburo.anytype.di.main + +import com.agileburo.anytype.domain.config.Config +import com.agileburo.anytype.domain.misc.UrlBuilder +import dagger.Module +import dagger.Provides +import javax.inject.Singleton + +@Module +class UtilModule { + + @Provides + @Singleton + fun provideUrlBuilder(config: Config): UrlBuilder { + return UrlBuilder(config) + } +} \ No newline at end of file diff --git a/blank.yml b/blank.yml deleted file mode 100644 index b2340b2446..0000000000 --- a/blank.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: CI - -on: [push] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Run a one-line script - run: echo Hello, world! - - name: Run a multi-line script - run: | - echo Add other actions to build, - echo test, and deploy your project. diff --git a/core-ui/build.gradle b/core-ui/build.gradle index e3a0f045cf..d423d517c9 100644 --- a/core-ui/build.gradle +++ b/core-ui/build.gradle @@ -28,6 +28,15 @@ android { includeAndroidResources = true } } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { diff --git a/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockView.kt b/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockView.kt index 87bedbdf0a..63629f4a45 100644 --- a/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockView.kt +++ b/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockView.kt @@ -269,12 +269,14 @@ sealed class BlockView : ViewType { * UI-model for blocks containing files. * @property id block's id * @property size a file's size - * @property filename a filename + * @property name a name + * @property size file size (in bytes) */ data class File( override val id: String, - val size: String, - val filename: String + val size: Long, + val name: String, + val mime: String ) : BlockView() { override fun getViewType() = HOLDER_FILE } @@ -330,9 +332,11 @@ sealed class BlockView : ViewType { /** * UI-model for a picture block * @property id block's id + * @property url url of the image file */ data class Picture( - override val id: String + override val id: String, + val url: String ) : BlockView() { override fun getViewType() = HOLDER_PICTURE } diff --git a/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockViewHolder.kt b/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockViewHolder.kt index 74c95e51f4..a4e81b8954 100644 --- a/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockViewHolder.kt +++ b/core-ui/src/main/java/com/agileburo/anytype/core_ui/features/page/BlockViewHolder.kt @@ -15,8 +15,10 @@ import com.agileburo.anytype.core_ui.features.page.BlockViewDiffUtil.Payload import com.agileburo.anytype.core_ui.tools.DefaultSpannableFactory import com.agileburo.anytype.core_ui.tools.DefaultTextWatcher import com.agileburo.anytype.core_ui.widgets.text.TextInputWidget +import com.agileburo.anytype.core_utils.const.MimeTypes import com.agileburo.anytype.core_utils.text.BackspaceKeyDetector import com.agileburo.anytype.core_utils.text.DefaultEnterKeyDetector +import com.bumptech.glide.Glide import kotlinx.android.synthetic.main.item_block_bookmark.view.* import kotlinx.android.synthetic.main.item_block_bulleted.view.* import kotlinx.android.synthetic.main.item_block_checkbox.view.* @@ -29,11 +31,13 @@ import kotlinx.android.synthetic.main.item_block_header_two.view.* import kotlinx.android.synthetic.main.item_block_highlight.view.* import kotlinx.android.synthetic.main.item_block_numbered.view.* import kotlinx.android.synthetic.main.item_block_page.view.* +import kotlinx.android.synthetic.main.item_block_picture.view.* import kotlinx.android.synthetic.main.item_block_task.view.* import kotlinx.android.synthetic.main.item_block_text.view.* import kotlinx.android.synthetic.main.item_block_title.view.* import kotlinx.android.synthetic.main.item_block_toggle.view.* import timber.log.Timber +import android.text.format.Formatter as FileSizeFormatter /** * Viewholder for rendering different type of blocks (i.e its UI-models). @@ -593,9 +597,14 @@ sealed class BlockViewHolder(view: View) : RecyclerView.ViewHolder(view) { private val name = itemView.filename fun bind(item: BlockView.File) { - name.text = item.filename - size.text = item.size - // TODO set file icon. + name.text = item.name + size.text = FileSizeFormatter.formatFileSize(itemView.context, item.size) + when (MimeTypes.category(item.mime)) { + MimeTypes.Category.PDF -> icon.setImageResource(R.drawable.ic_mime_pdf) + else -> { + // TODO add images when they are ready. + } + } } } @@ -636,8 +645,10 @@ sealed class BlockViewHolder(view: View) : RecyclerView.ViewHolder(view) { class Picture(view: View) : BlockViewHolder(view) { + private val image = itemView.image + fun bind(item: BlockView.Picture) { - // TODO + Glide.with(image).load(item.url).into(image) } } diff --git a/core-ui/src/main/res/drawable/ic_mime_pdf.xml b/core-ui/src/main/res/drawable/ic_mime_pdf.xml new file mode 100644 index 0000000000..28e2b4f879 --- /dev/null +++ b/core-ui/src/main/res/drawable/ic_mime_pdf.xml @@ -0,0 +1,13 @@ + + + + diff --git a/core-ui/src/main/res/layout/item_block_file.xml b/core-ui/src/main/res/layout/item_block_file.xml index 951cb79667..425f61cfd6 100644 --- a/core-ui/src/main/res/layout/item_block_file.xml +++ b/core-ui/src/main/res/layout/item_block_file.xml @@ -1,18 +1,18 @@ + android:orientation="horizontal" + android:paddingStart="@dimen/default_page_item_padding_start" + android:paddingEnd="@dimen/default_page_item_padding_end"> + tools:text="W. J. T. Mitchell — There Are No Visual Media.pdf" /> diff --git a/core-ui/src/main/res/layout/item_block_picture.xml b/core-ui/src/main/res/layout/item_block_picture.xml index b802212705..947c0361fb 100644 --- a/core-ui/src/main/res/layout/item_block_picture.xml +++ b/core-ui/src/main/res/layout/item_block_picture.xml @@ -1,19 +1,13 @@ - + android:layout_height="match_parent" /> + \ No newline at end of file diff --git a/core-utils/src/main/java/com/agileburo/anytype/core_utils/const/MimeTypes.kt b/core-utils/src/main/java/com/agileburo/anytype/core_utils/const/MimeTypes.kt new file mode 100644 index 0000000000..90da5702fd --- /dev/null +++ b/core-utils/src/main/java/com/agileburo/anytype/core_utils/const/MimeTypes.kt @@ -0,0 +1,20 @@ +package com.agileburo.anytype.core_utils.const + +object MimeTypes { + + private const val PDF = "application/pdf" + + private val IMAGES = listOf( + "image/jpeg" + ) + + enum class Category { + IMAGE, PDF, PICTURE, DOC, AUDIO, VIDEO, ZIP, OTHER + } + + fun category(mime: String): Category = when { + mime == PDF -> Category.PDF + IMAGES.contains(mime) -> Category.IMAGE + else -> Category.OTHER + } +} \ No newline at end of file diff --git a/data/src/main/java/com/agileburo/anytype/data/auth/repo/config/Configuration.kt b/data/src/main/java/com/agileburo/anytype/data/auth/repo/config/Configuration.kt new file mode 100644 index 0000000000..24303d97a3 --- /dev/null +++ b/data/src/main/java/com/agileburo/anytype/data/auth/repo/config/Configuration.kt @@ -0,0 +1,7 @@ +package com.agileburo.anytype.data.auth.repo.config + +import com.agileburo.anytype.data.auth.mapper.toDomain + +class Configuration(private val configurator: Configurator) { + fun init() = configurator.configure().toDomain() +} \ No newline at end of file diff --git a/data/src/main/java/com/agileburo/anytype/data/auth/repo/config/Configurator.kt b/data/src/main/java/com/agileburo/anytype/data/auth/repo/config/Configurator.kt new file mode 100644 index 0000000000..da0dc507d4 --- /dev/null +++ b/data/src/main/java/com/agileburo/anytype/data/auth/repo/config/Configurator.kt @@ -0,0 +1,7 @@ +package com.agileburo.anytype.data.auth.repo.config + +import com.agileburo.anytype.data.auth.model.ConfigEntity + +interface Configurator { + fun configure(): ConfigEntity +} \ No newline at end of file diff --git a/domain/src/main/java/com/agileburo/anytype/domain/block/model/Block.kt b/domain/src/main/java/com/agileburo/anytype/domain/block/model/Block.kt index 6a0c1ff44e..7542c91a55 100644 --- a/domain/src/main/java/com/agileburo/anytype/domain/block/model/Block.kt +++ b/domain/src/main/java/com/agileburo/anytype/domain/block/model/Block.kt @@ -140,6 +140,15 @@ data class Block( enum class Type { PAGE, DATA_VIEW, DASHBOARD, ARCHIVE } } + /** + * File block. + * @property hash file hash + * @property name filename + * @property mime mime type + * @property size file size (in bytes) + * @property type file type + * @property state file state + */ data class File( val hash: String, val name: String, diff --git a/domain/src/main/java/com/agileburo/anytype/domain/ext/BlockExt.kt b/domain/src/main/java/com/agileburo/anytype/domain/ext/BlockExt.kt index 499639ece2..2b316a5ecf 100644 --- a/domain/src/main/java/com/agileburo/anytype/domain/ext/BlockExt.kt +++ b/domain/src/main/java/com/agileburo/anytype/domain/ext/BlockExt.kt @@ -23,13 +23,19 @@ fun Map>.asRender(anchor: String): List { val children = getValue(anchor) val result = mutableListOf() children.forEach { child -> - if (child.content is Content.Text || child.content is Content.Image - || child.content is Content.Link || child.content is Content.Divider - ) { - result.add(child) - result.addAll(asRender(child.id)) - } else if (child.content is Content.Layout) - result.addAll(asRender(child.id)) + when (child.content) { + is Content.Text, + is Content.Image, + is Content.Link, + is Content.Divider, + is Content.File -> { + result.add(child) + result.addAll(asRender(child.id)) + } + is Content.Layout -> { + result.addAll(asRender(child.id)) + } + } } return result } diff --git a/domain/src/main/java/com/agileburo/anytype/domain/misc/UrlBuilder.kt b/domain/src/main/java/com/agileburo/anytype/domain/misc/UrlBuilder.kt new file mode 100644 index 0000000000..329dda67e6 --- /dev/null +++ b/domain/src/main/java/com/agileburo/anytype/domain/misc/UrlBuilder.kt @@ -0,0 +1,30 @@ +package com.agileburo.anytype.domain.misc + +import com.agileburo.anytype.domain.common.Url +import com.agileburo.anytype.domain.config.Config + +/** + * Helper class for building urls for files and images + * @property config configuration properties + */ +class UrlBuilder(val config: Config) { + + /** + * Builds image url for given [hash] + */ + fun image(hash: String): Url { + return config.gateway + IMAGE_PATH + hash + } + + /** + * Builds file url for given [hash] + */ + fun file(hash: String): Url { + return config.gateway + FILE_PATH + hash + } + + companion object { + const val IMAGE_PATH = "/image/" + const val FILE_PATH = "/file/" + } +} \ No newline at end of file diff --git a/middleware/src/main/java/com/agileburo/anytype/middleware/config/DefaultConfigurator.kt b/middleware/src/main/java/com/agileburo/anytype/middleware/config/DefaultConfigurator.kt new file mode 100644 index 0000000000..979b7a5de1 --- /dev/null +++ b/middleware/src/main/java/com/agileburo/anytype/middleware/config/DefaultConfigurator.kt @@ -0,0 +1,48 @@ +package com.agileburo.anytype.middleware.config + +import anytype.Commands.Rpc.Config +import com.agileburo.anytype.data.auth.model.ConfigEntity +import com.agileburo.anytype.data.auth.repo.config.Configurator +import lib.Lib + +/** + * Obtains middleware configuration data. + */ +class DefaultConfigurator : Configurator { + + override fun configure() = get() + + private val builder: () -> ConfigEntity = { + fetchConfig().let { response -> + ConfigEntity( + home = response.homeBlockId, + gateway = response.gatewayUrl + ) + } + } + + private var instance: ConfigEntity? = null + + fun get() = instance ?: builder().also { instance = it } + + fun new() = builder().also { instance = it } + + fun release() { + instance = null + } + + private fun fetchConfig(): Config.Get.Response { + val request = Config.Get.Request.newBuilder().build() + val encoded = Lib.configGet(request.toByteArray()) + val response = Config.Get.Response.parseFrom(encoded) + return parseResponse(response) + } + + private fun parseResponse(response: Config.Get.Response): Config.Get.Response { + return if (response.error != null && response.error.code != Config.Get.Response.Error.Code.NULL) { + throw Exception(response.error.description) + } else { + response + } + } +} \ No newline at end of file diff --git a/presentation/src/main/java/com/agileburo/anytype/presentation/mapper/MapperExtension.kt b/presentation/src/main/java/com/agileburo/anytype/presentation/mapper/MapperExtension.kt index bee186fa8d..8e946ac333 100644 --- a/presentation/src/main/java/com/agileburo/anytype/presentation/mapper/MapperExtension.kt +++ b/presentation/src/main/java/com/agileburo/anytype/presentation/mapper/MapperExtension.kt @@ -5,11 +5,13 @@ import com.agileburo.anytype.core_ui.features.page.BlockView import com.agileburo.anytype.domain.block.model.Block import com.agileburo.anytype.domain.block.model.Block.Content.Text.Style import com.agileburo.anytype.domain.dashboard.model.HomeDashboard +import com.agileburo.anytype.domain.misc.UrlBuilder import com.agileburo.anytype.presentation.desktop.DashboardView fun Block.toView( focused: Boolean = false, - numbers: Map = emptyMap() + numbers: Map = emptyMap(), + urlBuilder: UrlBuilder ): BlockView = when (val content = this.content) { is Block.Content.Text -> { when (content.style) { @@ -86,10 +88,20 @@ fun Block.toView( ) } } - is Block.Content.Image -> { - BlockView.Picture( - id = id - ) + is Block.Content.File -> { + when (content.type) { + Block.Content.File.Type.IMAGE -> BlockView.Picture( + id = id, + url = urlBuilder.image(content.hash) + ) + Block.Content.File.Type.FILE -> BlockView.File( + id = id, + size = content.size, + name = content.name, + mime = content.mime + ) + else -> TODO() + } } is Block.Content.Link -> { BlockView.Page( diff --git a/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModel.kt b/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModel.kt index 93937799f6..14b13f3bc9 100644 --- a/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModel.kt +++ b/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModel.kt @@ -19,6 +19,7 @@ import com.agileburo.anytype.domain.common.Id import com.agileburo.anytype.domain.event.interactor.InterceptEvents import com.agileburo.anytype.domain.event.model.Event import com.agileburo.anytype.domain.ext.* +import com.agileburo.anytype.domain.misc.UrlBuilder import com.agileburo.anytype.domain.page.ClosePage import com.agileburo.anytype.domain.page.CreatePage import com.agileburo.anytype.domain.page.OpenPage @@ -50,7 +51,8 @@ class PageViewModel( private val removeLinkMark: RemoveLinkMark, private val mergeBlocks: MergeBlocks, private val splitBlock: SplitBlock, - private val documentExternalEventReducer: StateReducer, Event> + private val documentExternalEventReducer: StateReducer, Event>, + private val urlBuilder: UrlBuilder ) : ViewStateViewModel(), SupportNavigation>, StateReducer, Event> by documentExternalEventReducer { @@ -258,14 +260,26 @@ class PageViewModel( is Content.Text -> { block.toView( focused = block.id == focus, - numbers = numbers + numbers = numbers, + urlBuilder = urlBuilder ) } is Content.Image -> { - block.toView() + block.toView( + urlBuilder = urlBuilder + ) } - is Content.Link -> block.toView() - is Content.Divider -> block.toView() + is Content.File -> { + block.toView( + urlBuilder = urlBuilder + ) + } + is Content.Link -> block.toView( + urlBuilder = urlBuilder + ) + is Content.Divider -> block.toView( + urlBuilder = urlBuilder + ) else -> null } } diff --git a/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModelFactory.kt b/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModelFactory.kt index 9bf0c0220b..15cfa56315 100644 --- a/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModelFactory.kt +++ b/presentation/src/main/java/com/agileburo/anytype/presentation/page/PageViewModelFactory.kt @@ -6,6 +6,7 @@ import com.agileburo.anytype.domain.block.interactor.* import com.agileburo.anytype.domain.block.model.Block import com.agileburo.anytype.domain.event.interactor.InterceptEvents import com.agileburo.anytype.domain.event.model.Event +import com.agileburo.anytype.domain.misc.UrlBuilder import com.agileburo.anytype.domain.page.ClosePage import com.agileburo.anytype.domain.page.CreatePage import com.agileburo.anytype.domain.page.OpenPage @@ -28,7 +29,8 @@ open class PageViewModelFactory( private val removeLinkMark: RemoveLinkMark, private val mergeBlocks: MergeBlocks, private val splitBlock: SplitBlock, - private val documentEventReducer: StateReducer, Event> + private val documentEventReducer: StateReducer, Event>, + private val urlBuilder: UrlBuilder ) : ViewModelProvider.Factory { @Suppress("UNCHECKED_CAST") @@ -50,7 +52,8 @@ open class PageViewModelFactory( mergeBlocks = mergeBlocks, splitBlock = splitBlock, createPage = createPage, - documentExternalEventReducer = documentEventReducer + documentExternalEventReducer = documentEventReducer, + urlBuilder = urlBuilder ) as T } } \ No newline at end of file