sample app (WIP)
This commit is contained in:
parent
2076b83675
commit
7e8ed3ea0b
@ -43,6 +43,11 @@ kapt {
|
|||||||
dependencies {
|
dependencies {
|
||||||
kapt project(':sample-utils:processor')
|
kapt project(':sample-utils:processor')
|
||||||
|
|
||||||
implementation 'io.noties:debug:5.1.0'
|
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
|
|
||||||
|
deps.with {
|
||||||
|
api it['x-recycler-view']
|
||||||
|
api it['adapt']
|
||||||
|
api it['debug']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1,14 @@
|
|||||||
[]
|
[
|
||||||
|
{
|
||||||
|
"javaClassName": "io.noties.markwon.app.samples.FirstSample",
|
||||||
|
"id": "202006164150023",
|
||||||
|
"title": "First Sample",
|
||||||
|
"description": "This **is** _the first_ sample",
|
||||||
|
"artifacts": [
|
||||||
|
"CORE"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"test"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
@ -2,13 +2,60 @@ package io.noties.markwon.app
|
|||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.ViewTreeObserver
|
||||||
|
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.noties.adapt.Adapt
|
||||||
|
import io.noties.debug.Debug
|
||||||
|
import io.noties.markwon.app.adapt.SampleItem
|
||||||
|
import io.noties.markwon.app.base.SearchBar
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||||
|
|
||||||
class MainActivity : Activity() {
|
class MainActivity : Activity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.activity_main)
|
||||||
|
|
||||||
/**/
|
val searchBar: SearchBar = findViewById(R.id.search_bar)
|
||||||
|
searchBar.onSearchListener = {
|
||||||
|
Debug.i("search: '$it'")
|
||||||
|
}
|
||||||
|
|
||||||
|
val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
|
||||||
|
recyclerView.layoutManager = LinearLayoutManager(this)
|
||||||
|
recyclerView.itemAnimator = DefaultItemAnimator()
|
||||||
|
recyclerView.setHasFixedSize(true)
|
||||||
|
recyclerView.clipToPadding = false
|
||||||
|
|
||||||
|
searchBar.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
|
||||||
|
override fun onPreDraw(): Boolean {
|
||||||
|
searchBar.viewTreeObserver.removeOnPreDrawListener(this)
|
||||||
|
recyclerView.setPadding(
|
||||||
|
recyclerView.paddingLeft,
|
||||||
|
recyclerView.paddingTop + searchBar.height,
|
||||||
|
recyclerView.paddingRight,
|
||||||
|
recyclerView.paddingBottom
|
||||||
|
)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
val adapt = Adapt.create()
|
||||||
|
recyclerView.adapter = adapt
|
||||||
|
|
||||||
|
val list = listOf(
|
||||||
|
MarkwonSampleItem(
|
||||||
|
"first",
|
||||||
|
"1",
|
||||||
|
"Title first",
|
||||||
|
"Description her egoes and goes ang goes, so will it ever stop?",
|
||||||
|
listOf(MarkwonArtifact.CORE, MarkwonArtifact.EDITOR),
|
||||||
|
listOf("first", "second")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
adapt.setItems(list.map { SampleItem(it) })
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package io.noties.markwon.app
|
||||||
|
|
||||||
|
abstract class MarkwonSample {
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package io.noties.markwon.app
|
||||||
|
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||||
|
|
||||||
|
data class MarkwonSampleItem(
|
||||||
|
val javaClassName: String,
|
||||||
|
val id: String,
|
||||||
|
val title: String,
|
||||||
|
val description: String,
|
||||||
|
val artifacts: List<MarkwonArtifact>,
|
||||||
|
val tags: List<String>
|
||||||
|
)
|
@ -0,0 +1,22 @@
|
|||||||
|
package io.noties.markwon.app.adapt
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import io.noties.adapt.Item
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||||
|
|
||||||
|
class ArtifactItem(artifact: MarkwonArtifact): Item<ArtifactItem.Holder>(artifact.name.hashCode().toLong()) {
|
||||||
|
|
||||||
|
override fun createHolder(inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||||
|
return Holder(inflater.inflate(0, parent, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(holder: Holder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder(itemView: View): Item.Holder(itemView) {
|
||||||
|
val textView: TextView = requireView(0)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package io.noties.markwon.app.adapt
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.text.Spannable
|
||||||
|
import android.text.SpannableStringBuilder
|
||||||
|
import android.text.TextPaint
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.text.style.ClickableSpan
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import io.noties.adapt.Item
|
||||||
|
import io.noties.debug.Debug
|
||||||
|
import io.noties.markwon.app.MarkwonSampleItem
|
||||||
|
import io.noties.markwon.app.R
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||||
|
|
||||||
|
class SampleItem(private val item: MarkwonSampleItem) : Item<SampleItem.Holder>(item.id.hashCode().toLong()) {
|
||||||
|
|
||||||
|
var search: String? = null
|
||||||
|
|
||||||
|
override fun createHolder(inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||||
|
val holder = Holder(inflater.inflate(R.layout.adapt_sample, parent, false))
|
||||||
|
holder.artifactsAndTags.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
return holder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun render(holder: Holder) {
|
||||||
|
holder.apply {
|
||||||
|
title.text = item.title
|
||||||
|
description.text = item.description
|
||||||
|
artifactsAndTags.text = buildArtifactsAndTags
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val buildArtifactsAndTags: CharSequence
|
||||||
|
get() {
|
||||||
|
val builder = SpannableStringBuilder()
|
||||||
|
|
||||||
|
item.artifacts
|
||||||
|
.forEach {
|
||||||
|
val length = builder.length
|
||||||
|
builder.append("\u00a0${it.name}\u00a0")
|
||||||
|
builder.setSpan(ArtifactSpan(it), length, builder.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!builder.isEmpty()) {
|
||||||
|
builder.append("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
item.tags
|
||||||
|
.forEach {
|
||||||
|
val length = builder.length
|
||||||
|
builder.append("\u00a0$it\u00a0")
|
||||||
|
builder.setSpan(TagSpan(it), length, builder.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder(itemView: View) : Item.Holder(itemView) {
|
||||||
|
val title: TextView = requireView(R.id.title)
|
||||||
|
val description: TextView = requireView(R.id.description)
|
||||||
|
val artifactsAndTags: TextView = requireView(R.id.artifacts_and_tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ArtifactSpan(val artifact: MarkwonArtifact) : ClickableSpan() {
|
||||||
|
override fun onClick(widget: View) {
|
||||||
|
Debug.i("clicked artifact: $artifact")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateDrawState(ds: TextPaint) {
|
||||||
|
ds.isUnderlineText = false
|
||||||
|
ds.bgColor = Color.GREEN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TagSpan(val tag: String) : ClickableSpan() {
|
||||||
|
override fun onClick(widget: View) {
|
||||||
|
Debug.i("clicked tag: $tag")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateDrawState(ds: TextPaint) {
|
||||||
|
ds.isUnderlineText = false
|
||||||
|
ds.bgColor = Color.BLUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package io.noties.markwon.app.base
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.ViewGroup
|
||||||
|
|
||||||
|
class FlowLayout(context: Context, attrs: AttributeSet) : ViewGroup(context, attrs) {
|
||||||
|
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
|
||||||
|
for (i in 0 until childCount) {
|
||||||
|
val child = getChildAt(i)
|
||||||
|
val params = child.layoutParams as LayoutParams
|
||||||
|
val left = paddingLeft + params.x
|
||||||
|
val top = paddingTop + params.y
|
||||||
|
child.layout(
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
left + child.measuredWidth,
|
||||||
|
top + child.measuredHeight
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||||
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateDefaultLayoutParams(): ViewGroup.LayoutParams {
|
||||||
|
return LayoutParams()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun checkLayoutParams(p: ViewGroup.LayoutParams?): Boolean {
|
||||||
|
return p is LayoutParams
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateLayoutParams(attrs: AttributeSet): ViewGroup.LayoutParams {
|
||||||
|
return LayoutParams(context, attrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateLayoutParams(p: ViewGroup.LayoutParams): ViewGroup.LayoutParams {
|
||||||
|
return LayoutParams(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
class LayoutParams : ViewGroup.LayoutParams {
|
||||||
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||||
|
constructor(width: Int, height: Int) : super(width, height)
|
||||||
|
constructor(params: ViewGroup.LayoutParams) : super(params)
|
||||||
|
constructor() : this(WRAP_CONTENT, WRAP_CONTENT)
|
||||||
|
|
||||||
|
var x: Int = 0
|
||||||
|
var y: Int = 0
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
package io.noties.markwon.app.base
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.Gravity
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import io.noties.markwon.app.R
|
||||||
|
import io.noties.markwon.app.utils.KeyEventUtils
|
||||||
|
import io.noties.markwon.app.utils.KeyboardUtils
|
||||||
|
import io.noties.markwon.app.utils.TextWatcherAdapter
|
||||||
|
import io.noties.markwon.app.utils.hidden
|
||||||
|
|
||||||
|
|
||||||
|
class SearchBar(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
|
||||||
|
|
||||||
|
private val focus: View
|
||||||
|
private val textField: TextField
|
||||||
|
private val clear: View
|
||||||
|
private val cancel: View
|
||||||
|
|
||||||
|
var onSearchListener: ((String?) -> Unit)? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
orientation = HORIZONTAL
|
||||||
|
gravity = Gravity.CENTER_VERTICAL
|
||||||
|
|
||||||
|
View.inflate(context, R.layout.view_search_bar, this)
|
||||||
|
|
||||||
|
focus = findViewById(R.id.focus)
|
||||||
|
textField = findViewById(R.id.text_field)
|
||||||
|
clear = findViewById(R.id.clear)
|
||||||
|
cancel = findViewById(R.id.cancel)
|
||||||
|
|
||||||
|
// listen for text state
|
||||||
|
textField.addTextChangedListener(TextWatcherAdapter.afterTextChanged {
|
||||||
|
textFieldChanged(it)
|
||||||
|
})
|
||||||
|
|
||||||
|
fun looseFocus() {
|
||||||
|
KeyboardUtils.hide(textField)
|
||||||
|
focus.requestFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
// on back pressed - lose focus and hide keyboard
|
||||||
|
textField.onBackPressedListener = {
|
||||||
|
// hide keyboard and lose focus
|
||||||
|
looseFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
textField.setOnFocusChangeListener { _, hasFocus ->
|
||||||
|
cancel.hidden = textField.text.isEmpty() && !hasFocus
|
||||||
|
}
|
||||||
|
|
||||||
|
textField.setOnEditorActionListener { _, _, event ->
|
||||||
|
if (KeyEventUtils.isActionUp(event)) {
|
||||||
|
looseFocus()
|
||||||
|
}
|
||||||
|
return@setOnEditorActionListener true
|
||||||
|
}
|
||||||
|
|
||||||
|
clear.setOnClickListener {
|
||||||
|
textField.setText("")
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel.setOnClickListener {
|
||||||
|
textField.setText("")
|
||||||
|
looseFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun textFieldChanged(text: CharSequence) {
|
||||||
|
val isEmpty = text.isEmpty()
|
||||||
|
clear.hidden = isEmpty
|
||||||
|
cancel.hidden = isEmpty && !textField.hasFocus()
|
||||||
|
|
||||||
|
onSearchListener?.invoke(if (text.isEmpty()) null else text.toString())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package io.noties.markwon.app.base
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.view.KeyEvent
|
||||||
|
import android.widget.EditText
|
||||||
|
import io.noties.markwon.app.utils.KeyEventUtils
|
||||||
|
|
||||||
|
class TextField(context: Context, attrs: AttributeSet?) : EditText(context, attrs) {
|
||||||
|
var onBackPressedListener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
override fun onDetachedFromWindow() {
|
||||||
|
onBackPressedListener = null
|
||||||
|
super.onDetachedFromWindow()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onKeyPreIme(keyCode: Int, event: KeyEvent?): Boolean {
|
||||||
|
if (isAttachedToWindow) {
|
||||||
|
onBackPressedListener?.also { listener ->
|
||||||
|
if (hasFocus()
|
||||||
|
&& KeyEvent.KEYCODE_BACK == keyCode
|
||||||
|
&& KeyEventUtils.isActionUp(event)) {
|
||||||
|
listener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.onKeyPreIme(keyCode, event)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package io.noties.markwon.app.samples
|
||||||
|
|
||||||
|
import io.noties.markwon.app.MarkwonSample
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||||
|
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||||
|
|
||||||
|
@MarkwonSampleInfo(
|
||||||
|
id = "202006164150023",
|
||||||
|
title = "First Sample",
|
||||||
|
description = "This **is** _the first_ sample",
|
||||||
|
artifacts = [MarkwonArtifact.CORE],
|
||||||
|
tags = ["test"]
|
||||||
|
)
|
||||||
|
class FirstSample : MarkwonSample() {
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package io.noties.markwon.app.utils
|
||||||
|
|
||||||
|
import android.view.KeyEvent
|
||||||
|
|
||||||
|
object KeyEventUtils {
|
||||||
|
fun isActionUp(event: KeyEvent?): Boolean {
|
||||||
|
return event == null || KeyEvent.ACTION_UP == event.action
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package io.noties.markwon.app.utils
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.inputmethod.InputMethodManager
|
||||||
|
|
||||||
|
object KeyboardUtils {
|
||||||
|
|
||||||
|
fun show(view: View) {
|
||||||
|
view.context.getSystemService(InputMethodManager::class.java)
|
||||||
|
?.showSoftInput(view, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hide(view: View) {
|
||||||
|
view.context.getSystemService(InputMethodManager::class.java)
|
||||||
|
?.hideSoftInputFromWindow(view.windowToken, 0)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package io.noties.markwon.app.utils;
|
||||||
|
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
public abstract class TextWatcherAdapter implements TextWatcher {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface AfterTextChanged {
|
||||||
|
void afterTextChanged(Editable s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static TextWatcher afterTextChanged(@NonNull AfterTextChanged afterTextChanged) {
|
||||||
|
return new TextWatcherAdapter() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
afterTextChanged.afterTextChanged(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package io.noties.markwon.app.utils
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
|
||||||
|
var View.hidden: Boolean
|
||||||
|
get() = visibility == GONE
|
||||||
|
set(value) {
|
||||||
|
visibility = if (value) GONE else VISIBLE
|
||||||
|
}
|
15
app-sample/src/main/res/drawable/bg_artifact.xml
Normal file
15
app-sample/src/main/res/drawable/bg_artifact.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_activated="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/red" />
|
||||||
|
<corners android:radius="128dip" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="@color/gray" />
|
||||||
|
<corners android:radius="128dip" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
13
app-sample/src/main/res/drawable/bg_tag.xml
Normal file
13
app-sample/src/main/res/drawable/bg_tag.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_activated="true">
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/red" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<shape>
|
||||||
|
<solid android:color="@color/accent" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
10
app-sample/src/main/res/drawable/ic_close_white_24dp.xml
Normal file
10
app-sample/src/main/res/drawable/ic_close_white_24dp.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="#FFFFFF"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
|
||||||
|
</vector>
|
10
app-sample/src/main/res/drawable/ic_search_white_24dp.xml
Normal file
10
app-sample/src/main/res/drawable/ic_search_white_24dp.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="#FFFFFF"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF000000"
|
||||||
|
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
|
||||||
|
</vector>
|
51
app-sample/src/main/res/layout/activity_main.xml
Normal file
51
app-sample/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?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:elevation="4dip"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
style="@style/AppBarIcon"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:padding="8dip"
|
||||||
|
android:src="@mipmap/ic_launcher" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginEnd="@dimen/app_bar_height"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/app_name"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
</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"
|
||||||
|
tools:translationY="56dip" />
|
||||||
|
|
||||||
|
<io.noties.markwon.app.base.SearchBar
|
||||||
|
android:id="@+id/search_bar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:padding="@dimen/content_padding" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
17
app-sample/src/main/res/layout/adapt_artifact.xml
Normal file
17
app-sample/src/main/res/layout/adapt_artifact.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"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/bg_artifact"
|
||||||
|
android:lines="1"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:paddingStart="@dimen/content_padding"
|
||||||
|
android:paddingTop="2dip"
|
||||||
|
android:paddingEnd="@dimen/content_padding"
|
||||||
|
android:paddingBottom="2dip"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
tools:text="core" />
|
51
app-sample/src/main/res/layout/adapt_sample.xml
Normal file
51
app-sample/src/main/res/layout/adapt_sample.xml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?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="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingTop="@dimen/content_padding"
|
||||||
|
android:paddingEnd="@dimen/content_padding"
|
||||||
|
android:paddingBottom="@dimen/content_padding"
|
||||||
|
tools:ignore="RtlSymmetry">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<!--textView instead of icon, so we align baseline-->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="@dimen/adapt_sample_hash_width"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="#"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textColor="?android:attr/colorSecondary"
|
||||||
|
tools:ignore="HardcodedText" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
tools:text="Title" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/adapt_sample_hash_width"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
tools:text="Description goes here" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/artifacts_and_tags"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/adapt_sample_hash_width"
|
||||||
|
tools:text="recycler-view adapt another" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
83
app-sample/src/main/res/layout/view_search_bar.xml
Normal file
83
app-sample/src/main/res/layout/view_search_bar.xml
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:background="#eee"
|
||||||
|
tools:gravity="center_vertical"
|
||||||
|
tools:layout_height="wrap_content"
|
||||||
|
tools:layout_widht="match_parent"
|
||||||
|
tools:orientation="horizontal"
|
||||||
|
tools:padding="@dimen/content_padding"
|
||||||
|
tools:parentTag="android.widget.LinearLayout">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="0px"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:paddingTop="@dimen/content_padding"
|
||||||
|
android:paddingBottom="@dimen/content_padding">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/focus"
|
||||||
|
android:layout_width="1px"
|
||||||
|
android:layout_height="1px"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true">
|
||||||
|
|
||||||
|
<requestFocus />
|
||||||
|
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="@dimen/search_bar_icon_side"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
android:src="@drawable/ic_search_white_24dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:tint="@color/gray" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/clear"
|
||||||
|
android:layout_width="@dimen/search_bar_icon_side"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end|center_vertical"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:scaleType="centerInside"
|
||||||
|
android:src="@drawable/ic_close_white_24dp"
|
||||||
|
android:tint="@color/gray"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<io.noties.markwon.app.base.TextField
|
||||||
|
android:id="@+id/text_field"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="@dimen/search_bar_icon_side"
|
||||||
|
android:layout_marginEnd="@dimen/search_bar_icon_side"
|
||||||
|
android:autofillHints="@null"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="@android:string/search_go"
|
||||||
|
android:inputType="textVisiblePassword"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
tools:ignore="UnusedAttribute" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cancel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/content_padding"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:padding="@dimen/content_padding"
|
||||||
|
android:text="@android:string/cancel"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="@color/accent"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</merge>
|
@ -1,4 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="accent">#5CB85C</color>
|
<color name="accent">#009900</color>
|
||||||
|
|
||||||
|
<color name="gray">#777777</color>
|
||||||
|
<color name="gray_light">#999999</color>
|
||||||
|
|
||||||
|
<color name="white">#FFFFFF</color>
|
||||||
|
<color name="window_background">#EEEEEE</color>
|
||||||
|
<color name="red">#FF0000</color>
|
||||||
</resources>
|
</resources>
|
10
app-sample/src/main/res/values/dimens.xml
Normal file
10
app-sample/src/main/res/values/dimens.xml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<dimen name="app_bar_height">56dip</dimen>
|
||||||
|
|
||||||
|
<dimen name="content_padding">8dip</dimen>
|
||||||
|
<dimen name="content_padding_double">16dip</dimen>
|
||||||
|
|
||||||
|
<dimen name="search_bar_icon_side">36dip</dimen>
|
||||||
|
<dimen name="adapt_sample_hash_width">36dip</dimen>
|
||||||
|
</resources>
|
@ -1,8 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<style name="AppThemeBase" parent="android:Theme.Material.Light.NoActionBar">
|
|
||||||
|
|
||||||
|
<style name="AppThemeBase" parent="android:Theme.Material.Light.NoActionBar">
|
||||||
|
<item name="android:colorAccent">@color/accent</item>
|
||||||
|
<item name="android:colorPrimary">@color/gray_light</item>
|
||||||
|
<item name="android:colorPrimaryDark">@color/gray</item>
|
||||||
|
<item name="android:windowBackground">@color/window_background</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme" parent="AppThemeBase" />
|
<style name="AppTheme" parent="AppThemeBase" />
|
||||||
|
|
||||||
|
<style name="AppBarContainer">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_height">@dimen/app_bar_height</item>
|
||||||
|
<item name="android:background">@color/gray_light</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppBarIcon">
|
||||||
|
<item name="android:layout_width">@dimen/app_bar_height</item>
|
||||||
|
<item name="android:layout_height">@dimen/app_bar_height</item>
|
||||||
|
<item name="android:scaleType">centerInside</item>
|
||||||
|
<item name="android:background">?android:attr/selectableItemBackgroundBorderless</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
64
art/ic_hash_white_24dp.svg
Normal file
64
art/ic_hash_white_24dp.svg
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
sodipodi:docname="ic_hash_white_24dp.svg"
|
||||||
|
inkscape:version="1.0beta2 (2b71d25, 2019-12-03)"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
height="24mm"
|
||||||
|
width="24mm">
|
||||||
|
<defs
|
||||||
|
id="defs2" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:window-y="23"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-height="813"
|
||||||
|
inkscape:window-width="1440"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:cy="75.396079"
|
||||||
|
inkscape:cx="72.78404"
|
||||||
|
inkscape:zoom="1.979899"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
id="base" />
|
||||||
|
<metadata
|
||||||
|
id="metadata5">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<g
|
||||||
|
style="font-style:normal;font-weight:normal;font-size:26.70579999999999998px;line-height:1.25;font-family:sans-serif;fill:#800000;fill-opacity:1;stroke:none;stroke-width:0.667646"
|
||||||
|
id="text12"
|
||||||
|
aria-label="#">
|
||||||
|
<path
|
||||||
|
id="path62"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:600;font-stretch:normal;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Semi-Bold';fill:#800000;stroke-width:0.667646"
|
||||||
|
d="m 16.28362,10.174409 -0.717197,3.703343 h 3.520785 v 2.19071 h -3.951103 l -1.043195,5.450695 h -2.321109 l 1.043195,-5.450695 H 9.5810905 L 8.5378953,21.519157 H 6.2689455 L 7.259981,16.068462 H 3.9999958 v -2.19071 H 7.6902991 L 8.4335757,10.174409 H 4.9910313 V 7.9836987 H 8.811734 L 9.8549293,2.4808436 h 2.3471897 l -1.043196,5.5028551 h 3.286066 l 1.043195,-5.5028551 h 2.26895 l -1.043196,5.5028551 h 3.286065 v 2.1907103 z m -6.2982913,3.703343 h 3.2599853 l 0.743277,-3.703343 h -3.259986 z" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
@ -77,8 +77,8 @@ ext {
|
|||||||
'jlatexmath-android' : 'ru.noties:jlatexmath-android:0.2.0',
|
'jlatexmath-android' : 'ru.noties:jlatexmath-android:0.2.0',
|
||||||
'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0',
|
'okhttp' : 'com.squareup.okhttp3:okhttp:3.9.0',
|
||||||
'prism4j' : 'io.noties:prism4j:2.0.0',
|
'prism4j' : 'io.noties:prism4j:2.0.0',
|
||||||
'debug' : 'io.noties:debug:5.0.0@jar',
|
'debug' : 'io.noties:debug:5.1.0',
|
||||||
'adapt' : 'io.noties:adapt:2.0.0',
|
'adapt' : 'io.noties:adapt:2.2.0',
|
||||||
'dagger' : "com.google.dagger:dagger:$daggerVersion",
|
'dagger' : "com.google.dagger:dagger:$daggerVersion",
|
||||||
'picasso' : 'com.squareup.picasso:picasso:2.71828',
|
'picasso' : 'com.squareup.picasso:picasso:2.71828',
|
||||||
'glide' : 'com.github.bumptech.glide:glide:4.9.0',
|
'glide' : 'com.github.bumptech.glide:glide:4.9.0',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user