diff --git a/app-sample/build.gradle b/app-sample/build.gradle index 9e4f0f23..0ea4fa44 100644 --- a/app-sample/build.gradle +++ b/app-sample/build.gradle @@ -45,19 +45,46 @@ androidExtensions { features = ["parcelize"] } +configurations.all { + exclude group: 'org.jetbrains', module: 'annotations-java5' +} + dependencies { kapt project(':sample-utils:processor') + deps['annotationProcessor'].with { + kapt it['prism4j-bundler'] + } implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation project(':markwon-core') + implementation project(':markwon-editor') + implementation project(':markwon-ext-latex') + implementation project(':markwon-ext-strikethrough') + implementation project(':markwon-ext-tables') + implementation project(':markwon-ext-tasklist') + implementation project(':markwon-html') + implementation project(':markwon-image') + implementation project(':markwon-inline-parser') + implementation project(':markwon-linkify') + implementation project(':markwon-recycler') + implementation project(':markwon-recycler-table') + implementation project(':markwon-simple-ext') + implementation project(':markwon-syntax-highlight') + + implementation project(':markwon-image-picasso') + implementation project(':markwon-image-glide') deps.with { implementation it['x-recycler-view'] implementation it['x-cardview'] implementation it['x-fragment'] + implementation it['okhttp'] + implementation it['prism4j'] implementation it['gson'] implementation it['adapt'] implementation it['debug'] + implementation it['android-svg'] + implementation it['android-gif'] } } diff --git a/app-sample/src/debug/res/layout/flowlayout_preview.xml b/app-sample/src/debug/res/layout/flowlayout_preview.xml index 4f9f98a1..c78c9d10 100644 --- a/app-sample/src/debug/res/layout/flowlayout_preview.xml +++ b/app-sample/src/debug/res/layout/flowlayout_preview.xml @@ -13,7 +13,7 @@ android:layout_height="wrap_content" android:text="Hey!" /> - - + - - + \ No newline at end of file diff --git a/app-sample/src/main/AndroidManifest.xml b/app-sample/src/main/AndroidManifest.xml index eed3ca3b..16c2d250 100644 --- a/app-sample/src/main/AndroidManifest.xml +++ b/app-sample/src/main/AndroidManifest.xml @@ -3,6 +3,8 @@ xmlns:tools="http://schemas.android.com/tools" package="io.noties.markwon.app"> + + - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app-sample/src/main/assets/README.md b/app-sample/src/main/assets/README.md new file mode 120000 index 00000000..ff5c7960 --- /dev/null +++ b/app-sample/src/main/assets/README.md @@ -0,0 +1 @@ +../../../../README.md \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/App.kt b/app-sample/src/main/java/io/noties/markwon/app/App.kt index 444ded43..41351f0c 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/App.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/App.kt @@ -3,6 +3,8 @@ package io.noties.markwon.app import android.app.Application import io.noties.debug.AndroidLogDebugOutput import io.noties.debug.Debug +import io.noties.markwon.app.sample.SampleManager +import java.util.concurrent.ExecutorService import java.util.concurrent.Executors @Suppress("unused") @@ -13,10 +15,12 @@ class App : Application() { Debug.init(AndroidLogDebugOutput(BuildConfig.DEBUG)) - sampleManager = SampleManager(this, Executors.newCachedThreadPool()) + executorService = Executors.newCachedThreadPool() + sampleManager = SampleManager(this, executorService) } companion object { + lateinit var executorService: ExecutorService lateinit var sampleManager: SampleManager } } \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/readme/GithubImageDestinationProcessor.kt b/app-sample/src/main/java/io/noties/markwon/app/readme/GithubImageDestinationProcessor.kt new file mode 100644 index 00000000..f94f3a5d --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/readme/GithubImageDestinationProcessor.kt @@ -0,0 +1,25 @@ +package io.noties.markwon.app.readme + +import android.net.Uri +import android.text.TextUtils +import io.noties.markwon.image.destination.ImageDestinationProcessor +import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute + +class GithubImageDestinationProcessor( + username: String = "noties", + repository: String = "Markwon", + branch: String = "master" +) : ImageDestinationProcessor() { + + private val processor = ImageDestinationProcessorRelativeToAbsolute("https://github.com/$username/$repository/raw/$branch/") + + override fun process(destination: String): String { + // process only images without scheme information + val uri = Uri.parse(destination) + return if (TextUtils.isEmpty(uri.scheme)) { + processor.process(destination) + } else { + destination + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/readme/ReadMeActivity.kt b/app-sample/src/main/java/io/noties/markwon/app/readme/ReadMeActivity.kt new file mode 100644 index 00000000..870c2b29 --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/readme/ReadMeActivity.kt @@ -0,0 +1,166 @@ +package io.noties.markwon.app.readme + +import android.app.Activity +import android.content.Context +import android.net.Uri +import android.os.Bundle +import android.view.View +import android.widget.TextView +import androidx.recyclerview.widget.DefaultItemAnimator +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import io.noties.debug.Debug +import io.noties.markwon.AbstractMarkwonPlugin +import io.noties.markwon.Markwon +import io.noties.markwon.MarkwonVisitor +import io.noties.markwon.app.R +import io.noties.markwon.app.utils.ReadMeUtils +import io.noties.markwon.app.utils.hidden +import io.noties.markwon.app.utils.loadReadMe +import io.noties.markwon.app.utils.textOrHide +import io.noties.markwon.ext.tasklist.TaskListPlugin +import io.noties.markwon.html.HtmlPlugin +import io.noties.markwon.image.ImagesPlugin +import io.noties.markwon.recycler.MarkwonAdapter +import io.noties.markwon.recycler.SimpleEntry +import io.noties.markwon.recycler.table.TableEntry +import io.noties.markwon.recycler.table.TableEntryPlugin +import io.noties.markwon.syntax.Prism4jThemeDefault +import io.noties.markwon.syntax.SyntaxHighlightPlugin +import io.noties.prism4j.Prism4j +import io.noties.prism4j.annotations.PrismBundle +import okhttp3.Call +import okhttp3.Callback +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import org.commonmark.ext.gfm.tables.TableBlock +import org.commonmark.node.FencedCodeBlock +import java.io.IOException + +@PrismBundle(includeAll = true) +class ReadMeActivity : Activity() { + + private lateinit var progressBar: View + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_read_me) + + progressBar = findViewById(R.id.progress_bar) + + val data = intent.data + + Debug.i(data) + + initAppBar(data) + + initRecyclerView(data) + } + + private val markwon: Markwon + get() = Markwon.builder(this) + .usePlugin(ImagesPlugin.create()) + .usePlugin(HtmlPlugin.create()) + .usePlugin(TableEntryPlugin.create(this)) + .usePlugin(SyntaxHighlightPlugin.create(Prism4j(GrammarLocatorDef()), Prism4jThemeDefault.create(0))) + .usePlugin(TaskListPlugin.create(this)) + .usePlugin(ReadMeImageDestinationPlugin(intent.data)) + .usePlugin(object : AbstractMarkwonPlugin() { + override fun configureVisitor(builder: MarkwonVisitor.Builder) { + builder.on(FencedCodeBlock::class.java) { visitor, block -> + // we actually won't be applying code spans here, as our custom view will + // draw background and apply mono typeface + // + // NB the `trim` operation on literal (as code will have a new line at the end) + val code = visitor.configuration() + .syntaxHighlight() + .highlight(block.info, block.literal.trim()) + visitor.builder().append(code) + } + } + }) + .build() + + private fun initAppBar(data: Uri?) { + val appBar = findViewById(R.id.app_bar) + appBar.findViewById(R.id.app_bar_icon).setOnClickListener { onBackPressed() } + + val (title: String, subtitle: String?) = if (data == null) { + Pair("README.md", null) + } else { + Pair(data.lastPathSegment ?: "", data.toString()) + } + + appBar.findViewById(R.id.title).text = title + appBar.findViewById(R.id.subtitle).textOrHide(subtitle) + } + + private fun initRecyclerView(data: Uri?) { + + val adapter = MarkwonAdapter.builder(R.layout.adapter_node, R.id.text_view) + .include(FencedCodeBlock::class.java, SimpleEntry.create(R.layout.adapter_node_code_block, R.id.text_view)) + .include(TableBlock::class.java, TableEntry.create { + it + .tableLayout(R.layout.adapter_node_table_block, R.id.table_layout) + .textLayoutIsRoot(R.layout.view_table_entry_cell) + }) + .build() + + val recyclerView: RecyclerView = findViewById(R.id.recycler_view) + recyclerView.layoutManager = LinearLayoutManager(this) + recyclerView.setHasFixedSize(true) + recyclerView.itemAnimator = DefaultItemAnimator() + recyclerView.adapter = adapter + + load(applicationContext, data) { result -> + + when (result) { + is Result.Failure -> Debug.e(result.throwable) + is Result.Success -> { + val markwon = markwon + val node = markwon.parse(result.markdown) + if (window != null) { + recyclerView.post { + adapter.setParsedMarkdown(markwon, node) + adapter.notifyDataSetChanged() + progressBar.hidden = true + } + } + } + } + } + } + + private sealed class Result { + data class Success(val markdown: String) : Result() + data class Failure(val throwable: Throwable) : Result() + } + + private companion object { + fun load(context: Context, data: Uri?, callback: (Result) -> Unit) = try { + + if (data == null) { + callback.invoke(Result.Success(loadReadMe(context))) + } else { + val request = Request.Builder() + .get() + .url(ReadMeUtils.buildRawGithubUrl(data)) + .build() + OkHttpClient().newCall(request).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + callback.invoke(Result.Failure(e)) + } + + override fun onResponse(call: Call, response: Response) { + val md = response.body()?.string() ?: "" + callback.invoke(Result.Success(md)) + } + }) + } + + } catch (t: Throwable) { + callback.invoke(Result.Failure(t)) + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/readme/ReadMeImageDestinationPlugin.kt b/app-sample/src/main/java/io/noties/markwon/app/readme/ReadMeImageDestinationPlugin.kt new file mode 100644 index 00000000..a4d25210 --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/readme/ReadMeImageDestinationPlugin.kt @@ -0,0 +1,21 @@ +package io.noties.markwon.app.readme + +import android.net.Uri +import io.noties.markwon.AbstractMarkwonPlugin +import io.noties.markwon.MarkwonConfiguration +import io.noties.markwon.app.utils.ReadMeUtils + +class ReadMeImageDestinationPlugin(private val data: Uri?) : AbstractMarkwonPlugin() { + override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { + val info = ReadMeUtils.parseInfo(data) + if (info == null) { + builder.imageDestinationProcessor(GithubImageDestinationProcessor()) + } else { + builder.imageDestinationProcessor(GithubImageDestinationProcessor( + username = info.username, + repository = info.repository, + branch = info.branch + )) + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/MainActivity.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/MainActivity.kt similarity index 84% rename from app-sample/src/main/java/io/noties/markwon/app/MainActivity.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/MainActivity.kt index f0fc8e35..e60c63d7 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/MainActivity.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/MainActivity.kt @@ -1,9 +1,9 @@ -package io.noties.markwon.app +package io.noties.markwon.app.sample import android.os.Bundle import android.view.Window import androidx.fragment.app.FragmentActivity -import io.noties.markwon.app.ui.SampleListFragment +import io.noties.markwon.app.sample.ui.SampleListFragment class MainActivity : FragmentActivity() { diff --git a/app-sample/src/main/java/io/noties/markwon/app/Sample.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/Sample.kt similarity index 92% rename from app-sample/src/main/java/io/noties/markwon/app/Sample.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/Sample.kt index ffb7c5bd..9ba5cd02 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/Sample.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/Sample.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app +package io.noties.markwon.app.sample import android.os.Parcelable import io.noties.markwon.sample.annotations.MarkwonArtifact diff --git a/app-sample/src/main/java/io/noties/markwon/app/adapt/SampleItem.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/SampleItem.kt similarity index 97% rename from app-sample/src/main/java/io/noties/markwon/app/adapt/SampleItem.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/SampleItem.kt index c294b874..56576f11 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/adapt/SampleItem.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/SampleItem.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.adapt +package io.noties.markwon.app.sample import android.text.Spanned import android.view.LayoutInflater @@ -8,8 +8,7 @@ import android.widget.TextView import io.noties.adapt.Item import io.noties.markwon.Markwon import io.noties.markwon.app.R -import io.noties.markwon.app.Sample -import io.noties.markwon.app.base.FlowLayout +import io.noties.markwon.app.widget.FlowLayout import io.noties.markwon.app.utils.displayName import io.noties.markwon.app.utils.hidden import io.noties.markwon.app.utils.tagDisplayName diff --git a/app-sample/src/main/java/io/noties/markwon/app/SampleManager.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/SampleManager.kt similarity index 98% rename from app-sample/src/main/java/io/noties/markwon/app/SampleManager.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/SampleManager.kt index 7addbabb..b45fd616 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/SampleManager.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/SampleManager.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app +package io.noties.markwon.app.sample import android.content.Context import io.noties.markwon.app.utils.Cancellable diff --git a/app-sample/src/main/java/io/noties/markwon/app/SampleSearch.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/SampleSearch.kt similarity index 91% rename from app-sample/src/main/java/io/noties/markwon/app/SampleSearch.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/SampleSearch.kt index 6f79aef4..2cc7a26e 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/SampleSearch.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/SampleSearch.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app +package io.noties.markwon.app.sample import io.noties.markwon.sample.annotations.MarkwonArtifact diff --git a/app-sample/src/main/java/io/noties/markwon/app/ui/MarkwonSample.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/MarkwonSample.kt similarity index 89% rename from app-sample/src/main/java/io/noties/markwon/app/ui/MarkwonSample.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/ui/MarkwonSample.kt index 67b78ccb..522acac1 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/ui/MarkwonSample.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/MarkwonSample.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.ui +package io.noties.markwon.app.sample.ui import android.view.LayoutInflater import android.view.View diff --git a/app-sample/src/main/java/io/noties/markwon/app/ui/MarkwonTextViewSample.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/MarkwonTextViewSample.kt similarity index 92% rename from app-sample/src/main/java/io/noties/markwon/app/ui/MarkwonTextViewSample.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/ui/MarkwonTextViewSample.kt index 58c4f5c8..64b767ec 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/ui/MarkwonTextViewSample.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/MarkwonTextViewSample.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.ui +package io.noties.markwon.app.sample.ui import android.content.Context import android.view.View diff --git a/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleCodeFragment.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleCodeFragment.kt new file mode 100644 index 00000000..fe4d95a5 --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleCodeFragment.kt @@ -0,0 +1,74 @@ +package io.noties.markwon.app.sample.ui + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.fragment.app.Fragment +import io.noties.markwon.app.App +import io.noties.markwon.app.R +import io.noties.markwon.app.sample.Sample +import io.noties.markwon.app.utils.hidden +import io.noties.markwon.app.utils.readCode +import io.noties.markwon.syntax.Prism4jSyntaxHighlight +import io.noties.markwon.syntax.Prism4jThemeDefault +import io.noties.prism4j.Prism4j +import io.noties.prism4j.annotations.PrismBundle + +@PrismBundle(include = ["java", "kotlin"], grammarLocatorClassName = ".GrammarLocatorSourceCode") +class SampleCodeFragment : Fragment() { + + private lateinit var progressBar: View + private lateinit var textView: TextView + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_sample_code, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + progressBar = view.findViewById(R.id.progress_bar) + textView = view.findViewById(R.id.text_view) + + load() + } + + private fun load() { + App.executorService.submit { + val code = sample.readCode(requireContext()) + val prism = Prism4j(GrammarLocatorSourceCode()) + val highlight = Prism4jSyntaxHighlight.create(prism, Prism4jThemeDefault.create(0)) + val language = when (code.language) { + Sample.Language.KOTLIN -> "kotlin" + Sample.Language.JAVA -> "java" + } + val text = highlight.highlight(language, code.sourceCode) + + textView.post { + //attached + if (context != null) { + progressBar.hidden = true + textView.text = text + } + } + } + } + + private val sample: Sample by lazy(LazyThreadSafetyMode.NONE) { + arguments!!.getParcelable(ARG_SAMPLE) + } + + companion object { + private const val ARG_SAMPLE = "arg.Sample" + + fun init(sample: Sample): SampleCodeFragment { + return SampleCodeFragment().apply { + arguments = Bundle().apply { + putParcelable(ARG_SAMPLE, sample) + } + } + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/ui/SampleFragment.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleFragment.kt similarity index 97% rename from app-sample/src/main/java/io/noties/markwon/app/ui/SampleFragment.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleFragment.kt index 59ca1533..f07f6de6 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/ui/SampleFragment.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleFragment.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.ui +package io.noties.markwon.app.sample.ui import android.os.Bundle import android.view.LayoutInflater @@ -8,7 +8,7 @@ import android.widget.TextView import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentTransaction import io.noties.markwon.app.R -import io.noties.markwon.app.Sample +import io.noties.markwon.app.sample.Sample import io.noties.markwon.app.utils.active class SampleFragment : Fragment() { diff --git a/app-sample/src/main/java/io/noties/markwon/app/ui/SampleListFragment.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleListFragment.kt similarity index 97% rename from app-sample/src/main/java/io/noties/markwon/app/ui/SampleListFragment.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleListFragment.kt index 57f906ca..fc68b7c8 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/ui/SampleListFragment.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SampleListFragment.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.ui +package io.noties.markwon.app.sample.ui import android.content.Context import android.os.Bundle @@ -19,11 +19,11 @@ import io.noties.debug.Debug import io.noties.markwon.Markwon import io.noties.markwon.app.App import io.noties.markwon.app.R -import io.noties.markwon.app.Sample -import io.noties.markwon.app.SampleManager -import io.noties.markwon.app.SampleSearch -import io.noties.markwon.app.adapt.SampleItem -import io.noties.markwon.app.base.SearchBar +import io.noties.markwon.app.sample.Sample +import io.noties.markwon.app.sample.SampleManager +import io.noties.markwon.app.sample.SampleSearch +import io.noties.markwon.app.sample.SampleItem +import io.noties.markwon.app.widget.SearchBar import io.noties.markwon.app.utils.Cancellable import io.noties.markwon.app.utils.displayName import io.noties.markwon.app.utils.onPreDraw diff --git a/app-sample/src/main/java/io/noties/markwon/app/ui/SamplePreviewFragment.kt b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SamplePreviewFragment.kt similarity index 93% rename from app-sample/src/main/java/io/noties/markwon/app/ui/SamplePreviewFragment.kt rename to app-sample/src/main/java/io/noties/markwon/app/sample/ui/SamplePreviewFragment.kt index 3bd64ce0..24e12c9f 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/ui/SamplePreviewFragment.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/sample/ui/SamplePreviewFragment.kt @@ -1,11 +1,11 @@ -package io.noties.markwon.app.ui +package io.noties.markwon.app.sample.ui import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment -import io.noties.markwon.app.Sample +import io.noties.markwon.app.sample.Sample class SamplePreviewFragment : Fragment() { diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/FirstSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/FirstSample.kt index cf20d3a5..cc4c512a 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/FirstSample.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/FirstSample.kt @@ -1,7 +1,7 @@ package io.noties.markwon.app.samples import io.noties.markwon.Markwon -import io.noties.markwon.app.ui.MarkwonTextViewSample +import io.noties.markwon.app.sample.ui.MarkwonTextViewSample import io.noties.markwon.sample.annotations.MarkwonArtifact import io.noties.markwon.sample.annotations.MarkwonSampleInfo diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/nested/SecondSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/nested/SecondSample.kt index c63e645e..6707dfea 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/nested/SecondSample.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/nested/SecondSample.kt @@ -1,7 +1,7 @@ package io.noties.markwon.app.samples.nested import io.noties.markwon.Markwon -import io.noties.markwon.app.ui.MarkwonTextViewSample +import io.noties.markwon.app.sample.ui.MarkwonTextViewSample import io.noties.markwon.sample.annotations.MarkwonArtifact import io.noties.markwon.sample.annotations.MarkwonSampleInfo diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/nested/ThirdSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/nested/ThirdSample.java index 2e7ef678..032d3eb2 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/nested/ThirdSample.java +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/nested/ThirdSample.java @@ -1,7 +1,7 @@ package io.noties.markwon.app.samples.nested; import io.noties.markwon.Markwon; -import io.noties.markwon.app.ui.MarkwonTextViewSample; +import io.noties.markwon.app.sample.ui.MarkwonTextViewSample; import io.noties.markwon.sample.annotations.MarkwonArtifact; import io.noties.markwon.sample.annotations.MarkwonSampleInfo; diff --git a/app-sample/src/main/java/io/noties/markwon/app/ui/SampleCodeFragment.kt b/app-sample/src/main/java/io/noties/markwon/app/ui/SampleCodeFragment.kt deleted file mode 100644 index e2de2050..00000000 --- a/app-sample/src/main/java/io/noties/markwon/app/ui/SampleCodeFragment.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.noties.markwon.app.ui - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.fragment.app.Fragment -import io.noties.markwon.app.R -import io.noties.markwon.app.Sample -import io.noties.markwon.app.utils.readCode - -class SampleCodeFragment : Fragment() { - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_sample_code, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val textView: TextView = view.findViewById(R.id.text_view) - val code = sample.readCode(requireContext()) - - textView.text = code.sourceCode - } - - private val sample: Sample by lazy(LazyThreadSafetyMode.NONE) { - arguments!!.getParcelable(ARG_SAMPLE) - } - - companion object { - private const val ARG_SAMPLE = "arg.Sample" - - fun init(sample: Sample): SampleCodeFragment { - return SampleCodeFragment().apply { - arguments = Bundle().apply { - putParcelable(ARG_SAMPLE, sample) - } - } - } - } -} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/utils/InputStreamUtils.kt b/app-sample/src/main/java/io/noties/markwon/app/utils/InputStreamUtils.kt new file mode 100644 index 00000000..d146a4c1 --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/utils/InputStreamUtils.kt @@ -0,0 +1,21 @@ +package io.noties.markwon.app.utils + +import java.io.IOException +import java.io.InputStream +import java.util.Scanner + +fun InputStream.readStringAndClose(): String { + try { + val scanner = Scanner(this).useDelimiter("\\A") + if (scanner.hasNext()) { + return scanner.next() + } + return "" + } finally { + try { + close() + } catch (e: IOException) { + // ignored + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/utils/ReadMeUtils.kt b/app-sample/src/main/java/io/noties/markwon/app/utils/ReadMeUtils.kt new file mode 100644 index 00000000..a6fbfebf --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/utils/ReadMeUtils.kt @@ -0,0 +1,44 @@ +package io.noties.markwon.app.utils + +import android.net.Uri +import java.util.regex.Pattern + +object ReadMeUtils { + // username, repo, branch, lastPathSegment + private val RE = Pattern.compile("^https:\\/\\/github\\.com\\/(\\w+?)\\/(\\w+?)\\/(?:blob|raw)\\/(\\w+?)\\/(.+)") + + data class GithubInfo( + val username: String, + val repository: String, + val branch: String, + val fileName: String + ) + + fun parseInfo(data: Uri?): GithubInfo? { + + if (data == null) { + return null + } + + val matcher = RE.matcher(data.toString()) + if (!matcher.matches()) { + return null + } + + return GithubInfo( + username = matcher.group(1), + repository = matcher.group(2), + branch = matcher.group(3), + fileName = matcher.group(4) + ) + } + + fun buildRawGithubUrl(data: Uri): String { + val info = parseInfo(data) + return if (info == null) { + data.toString() + } else { + "https://github.com/${info.username}/${info.repository}/raw/${info.branch}/${info.fileName}" + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtils.java b/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtils.java index 2f4195e3..2f500f9b 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtils.java +++ b/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtils.java @@ -12,7 +12,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; -import io.noties.markwon.app.Sample; +import io.noties.markwon.app.sample.Sample; public abstract class SampleUtils { diff --git a/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtilsKt.kt b/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtilsKt.kt index 6e88689c..dfbd8d27 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtilsKt.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/utils/SampleUtilsKt.kt @@ -1,10 +1,9 @@ package io.noties.markwon.app.utils import android.content.Context -import io.noties.markwon.app.Sample +import io.noties.markwon.app.sample.Sample import io.noties.markwon.sample.annotations.MarkwonArtifact import java.io.InputStream -import java.util.Scanner val MarkwonArtifact.displayName: String get() = "@${artifactName()}" @@ -22,11 +21,6 @@ fun Sample.readCode(context: Context): Sample.Code { .removePrefix(SAMPLE_PREFIX) .replace('.', '/') - // now, we have 2 possibilities -> Kotlin or Java - fun read(stream: InputStream): String { - return Scanner(stream).useDelimiter("\\A").next() - } - fun obtain(path: String): InputStream? { return try { assets.open(path) @@ -35,6 +29,7 @@ fun Sample.readCode(context: Context): Sample.Code { } } + // now, we have 2 possibilities -> Kotlin or Java var language: Sample.Language = Sample.Language.KOTLIN var stream = obtain("$path.kt") if (stream == null) { @@ -46,13 +41,12 @@ fun Sample.readCode(context: Context): Sample.Code { throw IllegalStateException("Cannot obtain sample file at path: $path") } - val code = read(stream) - - try { - stream.close() - } catch (t: Throwable) { - // ignore - } + val code = stream.readStringAndClose() return Sample.Code(language, code) +} + +fun loadReadMe(context: Context): String { + val stream = context.assets.open("README.md") + return stream.readStringAndClose() } \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/utils/TextViewUtils.kt b/app-sample/src/main/java/io/noties/markwon/app/utils/TextViewUtils.kt new file mode 100644 index 00000000..8ff0660a --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/utils/TextViewUtils.kt @@ -0,0 +1,9 @@ +package io.noties.markwon.app.utils + +import android.text.TextUtils +import android.widget.TextView + +fun TextView.textOrHide(text: CharSequence?) { + this.text = text + this.hidden = TextUtils.isEmpty(text) +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/base/FlowLayout.kt b/app-sample/src/main/java/io/noties/markwon/app/widget/FlowLayout.kt similarity index 99% rename from app-sample/src/main/java/io/noties/markwon/app/base/FlowLayout.kt rename to app-sample/src/main/java/io/noties/markwon/app/widget/FlowLayout.kt index be8fca71..a975f453 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/base/FlowLayout.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/widget/FlowLayout.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.base +package io.noties.markwon.app.widget import android.content.Context import android.util.AttributeSet diff --git a/app-sample/src/main/java/io/noties/markwon/app/base/SearchBar.kt b/app-sample/src/main/java/io/noties/markwon/app/widget/SearchBar.kt similarity index 98% rename from app-sample/src/main/java/io/noties/markwon/app/base/SearchBar.kt rename to app-sample/src/main/java/io/noties/markwon/app/widget/SearchBar.kt index ba4f644d..5c7508a1 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/base/SearchBar.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/widget/SearchBar.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.base +package io.noties.markwon.app.widget import android.content.Context import android.util.AttributeSet diff --git a/app-sample/src/main/java/io/noties/markwon/app/base/TextField.kt b/app-sample/src/main/java/io/noties/markwon/app/widget/TextField.kt similarity index 95% rename from app-sample/src/main/java/io/noties/markwon/app/base/TextField.kt rename to app-sample/src/main/java/io/noties/markwon/app/widget/TextField.kt index 0e826282..c6c627a8 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/base/TextField.kt +++ b/app-sample/src/main/java/io/noties/markwon/app/widget/TextField.kt @@ -1,4 +1,4 @@ -package io.noties.markwon.app.base +package io.noties.markwon.app.widget import android.content.Context import android.util.AttributeSet diff --git a/app-sample/src/main/res/layout/activity_read_me.xml b/app-sample/src/main/res/layout/activity_read_me.xml new file mode 100644 index 00000000..bb37ae71 --- /dev/null +++ b/app-sample/src/main/res/layout/activity_read_me.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app-sample/src/main/res/layout/adapt_sample.xml b/app-sample/src/main/res/layout/adapt_sample.xml index 2885673d..4b0d1b0c 100644 --- a/app-sample/src/main/res/layout/adapt_sample.xml +++ b/app-sample/src/main/res/layout/adapt_sample.xml @@ -54,7 +54,7 @@ android:textAppearance="?android:attr/textAppearance" tools:text="Description goes here" /> - - + - - + diff --git a/app-sample/src/main/res/layout/adapter_node.xml b/app-sample/src/main/res/layout/adapter_node.xml new file mode 100644 index 00000000..7ddaf140 --- /dev/null +++ b/app-sample/src/main/res/layout/adapter_node.xml @@ -0,0 +1,17 @@ + + \ No newline at end of file diff --git a/app-sample/src/main/res/layout/adapter_node_code_block.xml b/app-sample/src/main/res/layout/adapter_node_code_block.xml new file mode 100644 index 00000000..894e3835 --- /dev/null +++ b/app-sample/src/main/res/layout/adapter_node_code_block.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/app-sample/src/main/res/layout/adapter_node_table_block.xml b/app-sample/src/main/res/layout/adapter_node_table_block.xml new file mode 100644 index 00000000..aaaaa369 --- /dev/null +++ b/app-sample/src/main/res/layout/adapter_node_table_block.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/app-sample/src/main/res/layout/fragment_sample_code.xml b/app-sample/src/main/res/layout/fragment_sample_code.xml index d8ac6205..bdd14090 100644 --- a/app-sample/src/main/res/layout/fragment_sample_code.xml +++ b/app-sample/src/main/res/layout/fragment_sample_code.xml @@ -1,28 +1,41 @@ - - + android:layout_height="match_parent"> - + - + - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/app-sample/src/main/res/layout/fragment_sample_list.xml b/app-sample/src/main/res/layout/fragment_sample_list.xml index 353095ce..18dacbac 100644 --- a/app-sample/src/main/res/layout/fragment_sample_list.xml +++ b/app-sample/src/main/res/layout/fragment_sample_list.xml @@ -42,7 +42,7 @@ android:paddingBottom="36dip" tools:layout_marginTop="56dip" /> - - + \ No newline at end of file diff --git a/app-sample/src/main/res/values/dimens.xml b/app-sample/src/main/res/values/dimens.xml index 21ba14f5..1707aa4b 100644 --- a/app-sample/src/main/res/values/dimens.xml +++ b/app-sample/src/main/res/values/dimens.xml @@ -11,4 +11,7 @@ 1dip 56dip + + 64dip + \ No newline at end of file diff --git a/app-sample/src/main/res/values/strings.xml b/app-sample/src/main/res/values/strings.xml index 2ed0d912..4567d309 100644 --- a/app-sample/src/main/res/values/strings.xml +++ b/app-sample/src/main/res/values/strings.xml @@ -4,4 +4,5 @@ Preview Code + \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index b87cab5e..81d14d9e 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -60,6 +60,7 @@ dependencies { implementation it['debug'] implementation it['adapt'] implementation it['android-svg'] + implementation it['android-gif'] } deps['annotationProcessor'].with {