Skip to content

Commit

Permalink
Fix issues #43 #46, code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
kbiakov committed Jan 18, 2019
1 parent 0d689ca commit ed8e407
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 80 deletions.
143 changes: 64 additions & 79 deletions codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import io.github.kbiakov.codeview.highlight.color
/**
* @class CodeView
*
* View for showing code content with syntax highlighting.
* Display code with syntax highlighting.
*
* @author Kirill Biakov
*/
Expand All @@ -28,8 +28,9 @@ class CodeView @JvmOverloads constructor(
defStyleAttr: Int = 0
) : RelativeLayout(context, attrs, defStyleAttr) {

private val vCodeList: RecyclerView
private val vShadows: Map<ShadowPosition, View>
private val rvContent: RecyclerView
private val shadows: Map<ShadowPosition, View>
private val adapter get() = rvContent.adapter as? AbstractCodeAdapter<*>

/**
* Primary constructor.
Expand All @@ -38,12 +39,12 @@ class CodeView @JvmOverloads constructor(
inflate(context, R.layout.layout_code_view, this)
attrs?.let(::checkStartAnimation)

vCodeList = findViewById<RecyclerView>(R.id.rv_code_content).apply {
rvContent = findViewById<RecyclerView>(R.id.rv_content).apply {
layoutManager = LinearLayoutManager(context)
isNestedScrollingEnabled = true
}

vShadows = mapOf(
shadows = mapOf(
ShadowPosition.RightBorder to R.id.shadow_right_border,
ShadowPosition.NumBottom to R.id.shadow_num_bottom,
ShadowPosition.ContentBottom to R.id.shadow_content_bottom
Expand Down Expand Up @@ -78,39 +79,27 @@ class CodeView @JvmOverloads constructor(
}
}

/**
* Highlight code with defined programming language.
* It holds the placeholder on view until code is not highlighted.
*/
private fun highlight() {
getAdapter()?.apply {
highlight {
checkHighlightAnimation(::notifyDataSetChanged)
}
}
}

/**
* Border shadows will shown if full listing presented.
* It helps to see what part of code is scrolled & hidden.
* It helps to see which part of code is scrolled & hidden.
*
* @param isVisible Is shadows visible
*/
fun setupShadows(isVisible: Boolean) {
val visibility = if (isVisible) VISIBLE else GONE
val theme = getOptionsOrDefault().theme
vShadows.forEach { (pos, view) ->
val theme = optionsOrDefault.theme
shadows.forEach { (pos, view) ->
view.visibility = visibility
view.setSafeBackground(pos.createShadow(theme))
}
}

// - Initialization
// - Options

/**
* Prepare view with default adapter & options.
* View options accessor.
*/
private fun prepare() = setAdapter(CodeWithNotesAdapter(context))
private val optionsOrDefault get() = adapter?.options ?: Options(context)

/**
* Initialize with options.
Expand All @@ -119,102 +108,98 @@ class CodeView @JvmOverloads constructor(
*/
fun setOptions(options: Options) = setAdapter(CodeWithNotesAdapter(context, options))

/**
* Initialize with adapter.
*
* @param adapter Adapter
*/
fun setAdapter(adapter: AbstractCodeAdapter<*>) {
vCodeList.adapter = adapter
highlight()
}

// - Options

/**
* View options accessor.
*/
fun getOptions() = getAdapter()?.options
fun getOptionsOrDefault() = getOptions() ?: Options(context)

/**
* Update options or initialize if needed.
*
* @param options Options
*/
fun updateOptions(options: Options) {
getAdapter() ?: setOptions(options)
getAdapter()?.options = options
adapter
?.let { it.options = options }
?: setOptions(options)

setupShadows(options.shadows)
}

fun updateOptions(body: Options.() -> Unit) {
val options = getOptions() ?: getOptionsOrDefault()
updateOptions(options.apply(body))
}
/**
* Update options or initialize if needed.
*
* @param body Options mutator
*/
fun updateOptions(body: Options.() -> Unit) =
optionsOrDefault
.apply(body)
.apply(::updateOptions)

// - Adapter

/**
* Code adapter accessor.
* Initialize with adapter.
*
* Highlight code with defined programming language.
* It holds the placeholder on view until code is not highlighted.
*
* @param adapter Adapter
*/
fun getAdapter() = vCodeList.adapter as? AbstractCodeAdapter<*>
fun setAdapter(adapter: AbstractCodeAdapter<*>) {
rvContent.adapter = adapter.apply {
highlight { checkHighlightAnimation(::notifyDataSetChanged) }
}
}

/**
* Update adapter or initialize if needed.
*
* @param adapter Adapter
* @param isUseCurrent Use options that are already set or default
*/
fun updateAdapter(adapter: AbstractCodeAdapter<*>) {
adapter.options = getOptionsOrDefault()
setAdapter(adapter)
fun updateAdapter(adapter: AbstractCodeAdapter<*>, isUseCurrent: Boolean) {
setAdapter(adapter.apply {
if (isUseCurrent) {
options = optionsOrDefault
}
})
}

// - Set code

/**
* Set code content.
*
* There are two ways before code will be highlighted:
* 1) view is not initialized (adapter or options are not set),
* Set code content. View is:
* 1) not initialized (adapter or options is not set):
* prepare with default params & try to classify language
* 2) view initialized with some params, language:
* a) is set: used defined programming language
* 2) initialized (with some params), language is:
* a) set: use defined
* b) not set: try to classify
*
* @param code Code content
*/
fun setCode(code: String) {
getAdapter() ?: prepare()
getAdapter()?.updateCode(code)
}
fun setCode(code: String) = setCode(code, null)

/**
* Set code content.
*
* There are two ways before code will be highlighted:
* 1) view is not initialized, prepare with default params
* 2) view initialized with some params, set new language
* Set code content. View is:
* 1) not initialized: prepare with default params
* 2) initialized (with some params): set new language
*
* @param code Code content
* @param language Programming language
*/
fun setCode(code: String, language: String) {
val options = getOptionsOrDefault()
updateOptions(options.withLanguage(language))
getAdapter()?.updateCode(code)
fun setCode(code: String, language: String? = null) {
val options = optionsOrDefault.apply {
this.language = language
}
(adapter ?: CodeWithNotesAdapter(context, options)
.apply(::setAdapter))
.updateCode(code)
}

companion object {

private fun AttributeSet.isAnimateOnStart(context: Context): Boolean {
context.theme.obtainStyledAttributes(this, R.styleable.CodeView, 0, 0).apply {
val flag = getBoolean(R.styleable.CodeView_animateOnStart, false)
recycle()
return@isAnimateOnStart flag
}
return false
}
private fun AttributeSet.isAnimateOnStart(context: Context) =
context.theme.obtainStyledAttributes(this, R.styleable.CodeView, 0, 0).run {
val isAnimate = getBoolean(R.styleable.CodeView_animateOnStart, false)
recycle()
isAnimate
}

private fun View.setSafeBackground(newBackground: Drawable) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
Expand Down
2 changes: 1 addition & 1 deletion codeview/src/main/res/layout/layout_code_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
android:fillViewport="true">

<android.support.v7.widget.RecyclerView
android:id="@+id/rv_code_content"
android:id="@+id/rv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/item_code_line"/>
Expand Down

0 comments on commit ed8e407

Please sign in to comment.