Skip to content

Commit 22b0a8b

Browse files
authored
Merge pull request #32 from Softwee/develop
New customization, bugfixes & cleanup
2 parents 3250bdf + 23426cf commit 22b0a8b

33 files changed

+663
-498
lines changed

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ android:
1010
- tools # to get the new `repository-11.xml`
1111
- tools # to install latest Android SDK tools
1212
- platform-tools
13-
- build-tools-25.0.1
13+
- build-tools-25.0.3
1414
- android-25
1515
- extra-android-m2repository # Design Support library
16+
- android-21
1617
- sys-img-armeabi-v7a-android-21 # system image (emulator)
1718
licenses:
1819
- android-sdk-license-.+

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.0.3'
4+
ext.kotlin_version = '1.1.2-5'
55
repositories {
66
jcenter()
77
}
88
dependencies {
9-
classpath 'com.android.tools.build:gradle:2.2.2'
9+
classpath 'com.android.tools.build:gradle:2.3.3'
1010
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1111

1212
// NOTE: Do not place your application dependencies here; they belong

codeview/build.gradle

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,28 @@ apply plugin: 'kotlin-android'
33

44
android {
55
compileSdkVersion 25
6-
buildToolsVersion "25.0.1"
6+
buildToolsVersion '25.0.3'
77

88
defaultConfig {
99
minSdkVersion 15
1010
targetSdkVersion 25
1111
versionCode 1
12-
versionName "1.0"
12+
versionName '1.3.0'
1313
}
1414
buildTypes {
1515
release {
1616
minifyEnabled false
1717
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
1818
}
1919
}
20-
sourceSets {
21-
main.java.srcDirs += 'src/main/kotlin'
20+
lintOptions {
21+
abortOnError false
2222
}
2323
}
2424

2525
dependencies {
2626
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
2727

28-
compile 'com.android.support:appcompat-v7:25.0.1'
29-
compile 'com.android.support:recyclerview-v7:25.0.1'
30-
}
31-
repositories {
32-
mavenCentral()
33-
}
34-
buildscript {
28+
compile 'com.android.support:appcompat-v7:25.3.1'
29+
compile 'com.android.support:recyclerview-v7:25.3.1'
3530
}

codeview/src/main/AndroidManifest.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
xmlns:android="http://schemas.android.com/apk/res/android">
33

44
<application
5-
android:allowBackup="true"
65
android:label="@string/app_name"
76
android:supportsRtl="true">
87

96.2 KB
Binary file not shown.
674 KB
Binary file not shown.
327 KB
Binary file not shown.
93.7 KB
Binary file not shown.
58.5 KB
Binary file not shown.

codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt

Lines changed: 89 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.github.kbiakov.codeview
22

33
import android.content.Context
4+
import android.graphics.drawable.Drawable
5+
import android.graphics.drawable.GradientDrawable
46
import android.support.v7.widget.LinearLayoutManager
57
import android.support.v7.widget.RecyclerView
68
import android.util.AttributeSet
@@ -10,6 +12,8 @@ import io.github.kbiakov.codeview.Thread.delayed
1012
import io.github.kbiakov.codeview.adapters.AbstractCodeAdapter
1113
import io.github.kbiakov.codeview.adapters.CodeWithNotesAdapter
1214
import 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,59 +24,58 @@ import io.github.kbiakov.codeview.adapters.Options
2024
*/
2125
class 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 {
33-
val isAnimateOnStart = visibility == VISIBLE && { ctx: Context, ats: AttributeSet ->
34-
val a = ctx.theme.obtainStyledAttributes(ats, R.styleable.CodeView, 0, 0)
34+
inflate(context, R.layout.layout_code_view, this)
35+
checkStartAnimation(attrs)
3536

36-
try {
37-
a.getBoolean(R.styleable.CodeView_animateOnStart, true)
38-
} finally {
39-
a.recycle()
40-
}
41-
}(context, attrs)
37+
vCodeList = findViewById(R.id.rv_code_content) as RecyclerView
38+
vCodeList.layoutManager = LinearLayoutManager(context)
39+
vCodeList.isNestedScrollingEnabled = true
4240

43-
alpha = if (isAnimateOnStart) 0f else Consts.ALPHA
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+
}
4447

45-
inflate(context, R.layout.layout_code_view, this)
48+
private fun checkStartAnimation(attrs: AttributeSet) {
49+
if (visibility == VISIBLE && attrs.isAnimateOnStart(context)) {
50+
alpha = Const.Alpha.Invisible
4651

47-
if (isAnimateOnStart)
4852
animate()
49-
.setDuration(Consts.DELAY * 5)
50-
.alpha(Consts.ALPHA)
51-
52-
// TODO: add shadow color customization
53-
vShadowRight = findViewById(R.id.v_shadow_right)
54-
vShadowBottomLine = findViewById(R.id.v_shadow_bottom_line)
55-
vShadowBottomContent = findViewById(R.id.v_shadow_bottom_content)
53+
.setDuration(Const.DefaultDelay * 5)
54+
.alpha(Const.Alpha.Initial)
55+
} else
56+
alpha = Const.Alpha.Initial
57+
}
5658

57-
vCodeList = findViewById(R.id.rv_code_content) as RecyclerView
58-
vCodeList.layoutManager = LinearLayoutManager(context)
59-
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()
6069
}
6170

6271
/**
6372
* Highlight code with defined programming language.
6473
* It holds the placeholder on view until code is not highlighted.
6574
*/
6675
private fun highlight() {
67-
getAdapter()?.highlight {
68-
69-
animate()
70-
.setDuration(Consts.DELAY * 2)
71-
.alpha(.1f)
72-
73-
delayed {
74-
animate().alpha(1f)
75-
getAdapter()?.notifyDataSetChanged()
76+
getAdapter()?.apply {
77+
highlight {
78+
checkHighlightAnimation(this::notifyDataSetChanged)
7679
}
7780
}
7881
}
@@ -81,14 +84,15 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
8184
* Border shadows will shown if full listing presented.
8285
* It helps to see what part of code is scrolled & hidden.
8386
*
84-
* @param isShadows Is shadows needed
87+
* @param isVisible Is shadows visible
8588
*/
86-
private fun setupShadows(isShadows: Boolean) {
87-
val visibility = if (isShadows) VISIBLE else GONE
88-
89-
vShadowRight.visibility = visibility
90-
vShadowBottomLine.visibility = visibility
91-
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+
}
9296
}
9397

9498
// - Initialization
@@ -112,7 +116,6 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
112116
*/
113117
fun setAdapter(adapter: AbstractCodeAdapter<*>) {
114118
vCodeList.adapter = adapter
115-
setupShadows(adapter.options.shadows)
116119
highlight()
117120
}
118121

@@ -121,7 +124,7 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
121124
/**
122125
* View options accessor.
123126
*/
124-
fun getOptions(): Options? = getAdapter()?.options
127+
fun getOptions() = getAdapter()?.options
125128
fun getOptionsOrDefault() = getOptions() ?: Options(context)
126129

127130
/**
@@ -130,10 +133,14 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
130133
* @param options Options
131134
*/
132135
fun updateOptions(options: Options) {
133-
if (getAdapter() == null)
134-
setOptions(options)
135-
else
136-
getAdapter()!!.options = options
136+
getAdapter() ?: setOptions(options)
137+
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))
137144
}
138145

139146
// - Adapter
@@ -169,7 +176,7 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
169176
*/
170177
fun setCode(code: String) {
171178
getAdapter() ?: prepare()
172-
getAdapter()!!.updateCode(code)
179+
getAdapter()?.updateCode(code)
173180
}
174181

175182
/**
@@ -185,7 +192,40 @@ class CodeView(context: Context, attrs: AttributeSet) : RelativeLayout(context,
185192
fun setCode(code: String, language: String) {
186193
val options = getOptionsOrDefault()
187194
updateOptions(options.withLanguage(language))
188-
getAdapter()!!.updateCode(code)
195+
getAdapter()?.updateCode(code)
196+
}
197+
198+
companion object {
199+
200+
private fun AttributeSet.isAnimateOnStart(context: Context): Boolean {
201+
context.theme.obtainStyledAttributes(this, R.styleable.CodeView, 0, 0).apply {
202+
val flag = getBoolean(R.styleable.CodeView_animateOnStart, false)
203+
recycle()
204+
return@isAnimateOnStart flag
205+
}
206+
return false
207+
}
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+
}
189229
}
190230
}
191231

0 commit comments

Comments
 (0)