Sample app readme functionality
This commit is contained in:
parent
860d70d6d1
commit
45d205ba8c
@ -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']
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hey!" />
|
||||
|
||||
<io.noties.markwon.app.base.FlowLayout
|
||||
<io.noties.markwon.app.widget.FlowLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/content_padding"
|
||||
@ -86,9 +86,9 @@
|
||||
android:background="@drawable/bg_artifact"
|
||||
android:text="core" />
|
||||
|
||||
</io.noties.markwon.app.base.FlowLayout>
|
||||
</io.noties.markwon.app.widget.FlowLayout>
|
||||
|
||||
<io.noties.markwon.app.base.FlowLayout
|
||||
<io.noties.markwon.app.widget.FlowLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/content_padding"
|
||||
@ -161,6 +161,6 @@
|
||||
android:background="@drawable/bg_tag"
|
||||
android:text="core" />
|
||||
|
||||
</io.noties.markwon.app.base.FlowLayout>
|
||||
</io.noties.markwon.app.widget.FlowLayout>
|
||||
|
||||
</LinearLayout>
|
@ -3,6 +3,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.noties.markwon.app">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:name=".App"
|
||||
android:allowBackup="true"
|
||||
@ -13,12 +15,32 @@
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
|
||||
|
||||
<activity android:name=".MainActivity">
|
||||
<activity android:name=".sample.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".readme.ReadMeActivity"
|
||||
android:exported="true">
|
||||
|
||||
<!-- github markdown files handling -->
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="github.com"
|
||||
android:pathPattern=".*\\.md"
|
||||
android:scheme="https" />
|
||||
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
1
app-sample/src/main/assets/README.md
Symbolic link
1
app-sample/src/main/assets/README.md
Symbolic link
@ -0,0 +1 @@
|
||||
../../../../README.md
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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<View>(R.id.app_bar)
|
||||
appBar.findViewById<View>(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<TextView>(R.id.title).text = title
|
||||
appBar.findViewById<TextView>(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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -1,4 +1,4 @@
|
||||
package io.noties.markwon.app
|
||||
package io.noties.markwon.app.sample
|
||||
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
|
@ -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
|
@ -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
|
@ -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<Sample>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {
|
@ -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
|
@ -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() {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<Sample>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
@ -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}"
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -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()
|
||||
}
|
@ -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)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package io.noties.markwon.app.base
|
||||
package io.noties.markwon.app.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
@ -1,4 +1,4 @@
|
||||
package io.noties.markwon.app.base
|
||||
package io.noties.markwon.app.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
@ -1,4 +1,4 @@
|
||||
package io.noties.markwon.app.base
|
||||
package io.noties.markwon.app.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
70
app-sample/src/main/res/layout/activity_read_me.xml
Normal file
70
app-sample/src/main/res/layout/activity_read_me.xml
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
style="@style/AppBarContainer"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
style="@style/AppBarIcon"
|
||||
android:src="@drawable/ic_arrow_back_white_24dp"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginEnd="@dimen/content_padding"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
tools:text="README.md" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="middle"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textColor="@color/white"
|
||||
tools:text="https://blah.blah/README.md" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:overScrollMode="never"
|
||||
android:paddingTop="@dimen/content_padding"
|
||||
android:paddingBottom="36dip" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="@dimen/progress_bar_side"
|
||||
android:layout_height="@dimen/progress_bar_side"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
@ -54,7 +54,7 @@
|
||||
android:textAppearance="?android:attr/textAppearance"
|
||||
tools:text="Description goes here" />
|
||||
|
||||
<io.noties.markwon.app.base.FlowLayout
|
||||
<io.noties.markwon.app.widget.FlowLayout
|
||||
android:id="@+id/artifacts"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -66,9 +66,9 @@
|
||||
<!-- we are actually fine with pre-inflating a single view -->
|
||||
<include layout="@layout/view_artifact" />
|
||||
|
||||
</io.noties.markwon.app.base.FlowLayout>
|
||||
</io.noties.markwon.app.widget.FlowLayout>
|
||||
|
||||
<io.noties.markwon.app.base.FlowLayout
|
||||
<io.noties.markwon.app.widget.FlowLayout
|
||||
android:id="@+id/tags"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -80,7 +80,7 @@
|
||||
|
||||
<include layout="@layout/view_tag" />
|
||||
|
||||
</io.noties.markwon.app.base.FlowLayout>
|
||||
</io.noties.markwon.app.widget.FlowLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
17
app-sample/src/main/res/layout/adapter_node.xml
Normal file
17
app-sample/src/main/res/layout/adapter_node.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:breakStrategy="simple"
|
||||
android:hyphenationFrequency="none"
|
||||
android:lineSpacingExtra="2dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="#000"
|
||||
android:textSize="16sp"
|
||||
tools:text="Hello" />
|
26
app-sample/src/main/res/layout/adapter_node_code_block.xml
Normal file
26
app-sample/src/main/res/layout/adapter_node_code_block.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingRight="16dip"
|
||||
android:scrollbarStyle="outsideInset">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#0f000000"
|
||||
android:fontFamily="monospace"
|
||||
android:lineSpacingExtra="2dip"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingRight="16dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</HorizontalScrollView>
|
19
app-sample/src/main/res/layout/adapter_node_table_block.xml
Normal file
19
app-sample/src/main/res/layout/adapter_node_table_block.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:paddingLeft="16dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingRight="16dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:scrollbarStyle="outsideInset">
|
||||
|
||||
<TableLayout
|
||||
android:id="@+id/table_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:stretchColumns="*" />
|
||||
|
||||
</HorizontalScrollView>
|
@ -1,28 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<HorizontalScrollView
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:padding="@dimen/content_padding_double"
|
||||
android:scrollbarStyle="outsideInset">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:lineSpacingExtra="2dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="14sp"
|
||||
tools:text="package io.noties.markwon" />
|
||||
<HorizontalScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true"
|
||||
android:padding="@dimen/content_padding_double"
|
||||
android:scrollbarStyle="outsideInset">
|
||||
|
||||
</HorizontalScrollView>
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="monospace"
|
||||
android:lineSpacingExtra="2dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="14sp"
|
||||
tools:text="package io.noties.markwon" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</HorizontalScrollView>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
android:layout_width="@dimen/progress_bar_side"
|
||||
android:layout_height="@dimen/progress_bar_side"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
</FrameLayout>
|
@ -42,7 +42,7 @@
|
||||
android:paddingBottom="36dip"
|
||||
tools:layout_marginTop="56dip" />
|
||||
|
||||
<io.noties.markwon.app.base.SearchBar
|
||||
<io.noties.markwon.app.widget.SearchBar
|
||||
android:id="@+id/search_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
@ -51,7 +51,7 @@
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<io.noties.markwon.app.base.TextField
|
||||
<io.noties.markwon.app.widget.TextField
|
||||
android:id="@+id/text_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
9
app-sample/src/main/res/layout/view_table_entry_cell.xml
Normal file
9
app-sample/src/main/res/layout/view_table_entry_cell.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="#000"
|
||||
android:textSize="16sp"
|
||||
tools:text="Table content" />
|
@ -11,4 +11,7 @@
|
||||
|
||||
<dimen name="divider_height">1dip</dimen>
|
||||
<dimen name="tab_bar_height">56dip</dimen>
|
||||
|
||||
<dimen name="progress_bar_side">64dip</dimen>
|
||||
|
||||
</resources>
|
@ -4,4 +4,5 @@
|
||||
|
||||
<string name="tab_bar_preview">Preview</string>
|
||||
<string name="tab_bar_code">Code</string>
|
||||
|
||||
</resources>
|
@ -60,6 +60,7 @@ dependencies {
|
||||
implementation it['debug']
|
||||
implementation it['adapt']
|
||||
implementation it['android-svg']
|
||||
implementation it['android-gif']
|
||||
}
|
||||
|
||||
deps['annotationProcessor'].with {
|
||||
|
Loading…
x
Reference in New Issue
Block a user