11package io.github.kbiakov.codeview
22
33import android.content.Context
4+ import android.graphics.drawable.Drawable
5+ import android.graphics.drawable.GradientDrawable
46import android.support.v7.widget.LinearLayoutManager
57import android.support.v7.widget.RecyclerView
68import android.util.AttributeSet
@@ -10,6 +12,8 @@ import io.github.kbiakov.codeview.Thread.delayed
1012import io.github.kbiakov.codeview.adapters.AbstractCodeAdapter
1113import io.github.kbiakov.codeview.adapters.CodeWithNotesAdapter
1214import io.github.kbiakov.codeview.adapters.Options
15+ import io.github.kbiakov.codeview.highlight.ColorThemeData
16+ import io.github.kbiakov.codeview.highlight.color
1317
1418/* *
1519 * @class CodeView
@@ -20,52 +24,58 @@ import io.github.kbiakov.codeview.adapters.Options
2024 */
2125class CodeView (context : Context , attrs : AttributeSet ) : RelativeLayout(context, attrs) {
2226
23- private val vShadowRight: View
24- private val vShadowBottomLine: View
25- private val vShadowBottomContent: View
26-
2727 private val vCodeList: RecyclerView
28+ private val vShadows: Map <ShadowPosition , View >
2829
2930 /* *
3031 * Primary constructor.
3132 */
3233 init {
3334 inflate(context, R .layout.layout_code_view, this )
35+ checkStartAnimation(attrs)
36+
37+ vCodeList = findViewById(R .id.rv_code_content) as RecyclerView
38+ vCodeList.layoutManager = LinearLayoutManager (context)
39+ vCodeList.isNestedScrollingEnabled = true
40+
41+ vShadows = mapOf (
42+ ShadowPosition .RightBorder to R .id.shadow_right_border,
43+ ShadowPosition .NumBottom to R .id.shadow_num_bottom,
44+ ShadowPosition .ContentBottom to R .id.shadow_content_bottom
45+ ).mapValues { findViewById(it.value) }
46+ }
3447
35- if (visibility == VISIBLE && isAnimateOnStart(context, attrs)) {
48+ private fun checkStartAnimation (attrs : AttributeSet ) {
49+ if (visibility == VISIBLE && attrs.isAnimateOnStart(context)) {
3650 alpha = Const .Alpha .Invisible
3751
3852 animate()
3953 .setDuration(Const .DefaultDelay * 5 )
4054 .alpha(Const .Alpha .Initial )
41- } else {
55+ } else
4256 alpha = Const .Alpha .Initial
43- }
44-
45- // TODO: add shadow color customization
46- vShadowRight = findViewById(R .id.v_shadow_right)
47- vShadowBottomLine = findViewById(R .id.v_shadow_bottom_line)
48- vShadowBottomContent = findViewById(R .id.v_shadow_bottom_content)
57+ }
4958
50- vCodeList = findViewById(R .id.rv_code_content) as RecyclerView
51- vCodeList.layoutManager = LinearLayoutManager (context)
52- vCodeList.isNestedScrollingEnabled = true
59+ private fun AbstractCodeAdapter <* >.checkHighlightAnimation (action : () -> Unit ) {
60+ if (options.animateOnHighlight) {
61+ animate()
62+ .setDuration(Const .DefaultDelay * 2 )
63+ .alpha(Const .Alpha .AlmostInvisible )
64+ delayed {
65+ animate().alpha(Const .Alpha .Visible )
66+ action()
67+ }
68+ } else action()
5369 }
5470
5571 /* *
5672 * Highlight code with defined programming language.
5773 * It holds the placeholder on view until code is not highlighted.
5874 */
5975 private fun highlight () {
60- getAdapter()?.highlight {
61-
62- animate()
63- .setDuration(Const .DefaultDelay * 2 )
64- .alpha(.1f )
65-
66- delayed {
67- animate().alpha(1f )
68- getAdapter()?.notifyDataSetChanged()
76+ getAdapter()?.apply {
77+ highlight {
78+ checkHighlightAnimation(this ::notifyDataSetChanged)
6979 }
7080 }
7181 }
@@ -74,14 +84,15 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
7484 * Border shadows will shown if full listing presented.
7585 * It helps to see what part of code is scrolled & hidden.
7686 *
77- * @param isShadows Is shadows needed
87+ * @param isVisible Is shadows visible
7888 */
79- private fun setupShadows (isShadows : Boolean ) {
80- val visibility = if (isShadows) VISIBLE else GONE
81-
82- vShadowRight.visibility = visibility
83- vShadowBottomLine.visibility = visibility
84- vShadowBottomContent.visibility = visibility
89+ fun setupShadows (isVisible : Boolean ) {
90+ val visibility = if (isVisible) VISIBLE else GONE
91+ val theme = getOptionsOrDefault().theme
92+ vShadows.forEach { (pos, view) ->
93+ view.visibility = visibility
94+ view.setSafeBackground(pos.createShadow(theme))
95+ }
8596 }
8697
8798 // - Initialization
@@ -105,7 +116,6 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
105116 */
106117 fun setAdapter (adapter : AbstractCodeAdapter <* >) {
107118 vCodeList.adapter = adapter
108- setupShadows(adapter.options.shadows)
109119 highlight()
110120 }
111121
@@ -125,6 +135,12 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
125135 fun updateOptions (options : Options ) {
126136 getAdapter() ? : setOptions(options)
127137 getAdapter()?.options = options
138+ setupShadows(options.shadows)
139+ }
140+
141+ fun updateOptions (body : Options .() -> Unit ) {
142+ val options = getOptions() ? : getOptionsOrDefault()
143+ updateOptions(options.apply (body))
128144 }
129145
130146 // - Adapter
@@ -181,14 +197,35 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
181197
182198 companion object {
183199
184- private fun isAnimateOnStart (context : Context , attr : AttributeSet ): Boolean {
185- context.theme.obtainStyledAttributes(attr , R .styleable.CodeView , 0 , 0 ).apply {
200+ private fun AttributeSet. isAnimateOnStart (context : Context ): Boolean {
201+ context.theme.obtainStyledAttributes(this , R .styleable.CodeView , 0 , 0 ).apply {
186202 val flag = getBoolean(R .styleable.CodeView_animateOnStart , false )
187203 recycle()
188204 return @isAnimateOnStart flag
189205 }
190206 return false
191207 }
208+
209+ private fun View.setSafeBackground (newBackground : Drawable ) {
210+ if (android.os.Build .VERSION .SDK_INT >= android.os.Build .VERSION_CODES .JELLY_BEAN ) {
211+ background = newBackground
212+ }
213+ }
214+ }
215+
216+ private enum class ShadowPosition {
217+ RightBorder ,
218+ NumBottom ,
219+ ContentBottom ;
220+
221+ fun createShadow (theme : ColorThemeData ) = when (this ) {
222+ RightBorder -> GradientDrawable .Orientation .LEFT_RIGHT to theme.bgContent
223+ NumBottom -> GradientDrawable .Orientation .TOP_BOTTOM to theme.bgNum
224+ ContentBottom -> GradientDrawable .Orientation .TOP_BOTTOM to theme.bgContent
225+ }.let {
226+ val colors = arrayOf(android.R .color.transparent, it.second)
227+ GradientDrawable (it.first, colors.map(Int ::color).toIntArray())
228+ }
192229 }
193230}
194231
0 commit comments