From d6267e5e0def48a1808f766ba1cb93fcb5e26600 Mon Sep 17 00:00:00 2001 From: Kirill Biakov Date: Fri, 26 Aug 2016 13:45:49 +0300 Subject: [PATCH 1/6] Code line click listener upgraded --- .../java/io/github/kbiakov/codeview/CodeContentAdapter.kt | 2 +- codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt | 4 ++-- .../io/github/kbiakov/codeviewexample/ListingsActivity.java | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt index 8a89324..5b90ca5 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt @@ -178,7 +178,7 @@ class CodeContentAdapter : RecyclerView.Adapter { holder.mItem = codeLine holder.itemView.setOnClickListener { - codeListener?.onCodeLineClicked(position) + codeListener?.onCodeLineClicked(position + 1, codeLine) } holder.tvLineContent.text = html(codeLine) diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt index dbde06e..40374a0 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt @@ -264,7 +264,7 @@ class CodeView : RelativeLayout { val lineHeight = dpToPx(context, 24) val topPadding = dpToPx(context, 8) - // double padding (top & bottom) for big view, one is enough for small + // double padding (top & bottom), one is enough for single line view val padding = (if (linesCount > 1) 2 else 1) * topPadding val height = linesCount * lineHeight + padding @@ -296,7 +296,7 @@ class CodeView : RelativeLayout { * Provides listener to code line clicks. */ interface OnCodeLineClickListener { - fun onCodeLineClicked(n: Int) + fun onCodeLineClicked(n: Int, line: String) } /** diff --git a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java index 036c3fa..be33f46 100644 --- a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java +++ b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java @@ -2,9 +2,7 @@ import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; -import android.util.Log; import io.github.kbiakov.codeview.CodeView; import io.github.kbiakov.codeview.highlight.ColorTheme; From b07530bc8aa35a2f580c3a615ae64b8bc7f4794c Mon Sep 17 00:00:00 2001 From: Kirill Biakov Date: Fri, 26 Aug 2016 18:39:39 +0300 Subject: [PATCH 2/6] Added ability to add own view under line --- .../kbiakov/codeview/CodeContentAdapter.kt | 80 +++++++++++++++---- .../io/github/kbiakov/codeview/CodeView.kt | 19 +++++ .../github/kbiakov/codeview/LineNoteView.kt | 17 ++++ .../src/main/res/layout/item_code_line.xml | 12 ++- .../codeviewexample/ListingsActivity.java | 14 +++- 5 files changed, 124 insertions(+), 18 deletions(-) create mode 100644 codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt index 5b90ca5..f668700 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt @@ -5,6 +5,8 @@ import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.RelativeLayout import android.widget.TextView import io.github.kbiakov.codeview.classifier.CodeProcessor import io.github.kbiakov.codeview.highlight.* @@ -32,6 +34,12 @@ class CodeContentAdapter : RecyclerView.Adapter { internal var codeListener: OnCodeLineClickListener? + internal var lineNotes: HashMap> + set(lineNotes) { + field = lineNotes + notifyDataSetChanged() + } + internal var colorTheme: ColorThemeData set(colorTheme) { field = colorTheme @@ -42,6 +50,7 @@ class CodeContentAdapter : RecyclerView.Adapter { mLines = ArrayList() mDroppedLines = null isFullShowing = true + lineNotes = HashMap() colorTheme = ColorTheme.SOLARIZED_LIGHT.with() } @@ -81,7 +90,7 @@ class CodeContentAdapter : RecyclerView.Adapter { * @param shortcutNote Note will shown below code for listing shortcut */ private fun initCodeContent(isShowFull: Boolean, - shortcutNote: String = mContext.getString(R.string.show_all)) { + shortcutNote: String = showAllBottomNote()) { var lines: MutableList = ArrayList(extractLines(mContent)) isFullShowing = isShowFull || lines.size <= mMaxLines // limit is not reached @@ -106,6 +115,18 @@ class CodeContentAdapter : RecyclerView.Adapter { notifyDataSetChanged() } + /** + * Add note to code line. + * + * @param num Line number + * @param note Note content + */ + fun addLineNote(num: Int, note: String) { + val notes = lineNotes[num] ?: ArrayList() + lineNotes.put(num, notes + note) + notifyDataSetChanged() + } + /** * Highlight code content. * @@ -134,7 +155,7 @@ class CodeContentAdapter : RecyclerView.Adapter { } } - // - Helpers + // - Helpers (for accessors) private fun updateContent(codeLines: List, onUpdated: () -> Unit) { ui { @@ -153,6 +174,8 @@ class CodeContentAdapter : RecyclerView.Adapter { updateContent(lines, onReady) } + private fun showAllBottomNote() = mContext.getString(R.string.show_all) + private fun monoTypeface() = MonoFontCache.getInstance(mContext).typeface // - View holder @@ -178,10 +201,20 @@ class CodeContentAdapter : RecyclerView.Adapter { holder.mItem = codeLine holder.itemView.setOnClickListener { - codeListener?.onCodeLineClicked(position + 1, codeLine) + codeListener?.onCodeLineClicked(position, codeLine) } - holder.tvLineContent.text = html(codeLine) + setupLine(position, codeLine, holder) + displayLineNotes(position, holder) + addExtraPadding(position, holder) + } + + override fun getItemCount() = mLines.size + + // Helpers (for view holder) + + private fun setupLine(position: Int, line: String, holder: ViewHolder) { + holder.tvLineContent.text = html(line) if (!isFullShowing && position == MAX_SHORTCUT_LINES) { holder.tvLineNum.textSize = 10f @@ -191,31 +224,44 @@ class CodeContentAdapter : RecyclerView.Adapter { holder.tvLineNum.textSize = 12f holder.tvLineNum.text = "${position + 1}" } - - addExtraPadding(position, holder.itemView, holder.tvLineNum, holder.tvLineContent) } - override fun getItemCount() = mLines.size + private fun displayLineNotes(position: Int, holder: ViewHolder) { + val notes = lineNotes[position] + + holder.llLineNotes.removeAllViews() - private fun addExtraPadding(position: Int, itemView: View, - tvLineNum: TextView, tvLineContent: TextView) { + notes?.let { + holder.llLineNotes.visibility = if (it.isNotEmpty()) View.VISIBLE else View.GONE + + it.forEach { note -> + val noteView = LineNoteView.create(mContext, note, colorTheme.noteColor.color()) + holder.llLineNotes.addView(noteView) + } + } + } + + private fun addExtraPadding(position: Int, holder: ViewHolder) { val dp8 = dpToPx(mContext, 8) val isFirst = position == 0 val isLast = position == itemCount - 1 if (isFirst || isLast) { - itemView.layoutParams.height = dp8 * 4 + // itemView.layoutParams.height = dp8 * 4 val topPadding = if (isFirst) dp8 else 0 val bottomPadding = if (isLast) dp8 else 0 - tvLineNum.setPadding(0, topPadding, 0, bottomPadding) - tvLineContent.setPadding(0, topPadding, 0, bottomPadding) + holder.tvLineNum.setPadding(0, topPadding, 0, bottomPadding) + holder.tvLineContent.setPadding(0, topPadding, 0, bottomPadding) } else { - itemView.layoutParams.height = dp8 * 3 + // itemView.layoutParams.height = dp8 * 3 - tvLineNum.setPadding(0, 0, 0, 0) - tvLineContent.setPadding(0, 0, 0, 0) + holder.tvLineNum.setPadding(0, 0, 0, 0) + holder.tvLineContent.setPadding(0, 0, 0, 0) } + + // TODO: measure height + // holder.tvLineNum.layoutParams.height = holder.itemView.layoutParams.height } companion object { @@ -225,12 +271,16 @@ class CodeContentAdapter : RecyclerView.Adapter { class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var tvLineNum: TextView var tvLineContent: TextView + var rlLineBlock: RelativeLayout + var llLineNotes: LinearLayout var mItem: String? = null init { tvLineNum = itemView.findViewById(R.id.tv_line_num) as TextView tvLineContent = itemView.findViewById(R.id.tv_line_content) as TextView + rlLineBlock = itemView.findViewById(R.id.rl_line_block) as RelativeLayout + llLineNotes = itemView.findViewById(R.id.ll_line_notes) as LinearLayout } override fun toString() = "${super.toString()} '$mItem'" diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt index 40374a0..d1b3fa2 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt @@ -192,6 +192,25 @@ class CodeView : RelativeLayout { vShadowBottomContent.visibility = visibility } + /** + * Add notes to code snippet. + * + * @param notes Map of notes (line number -> list of notes) + */ + fun addLineNotes(notes: HashMap>) = addTask { + adapter.lineNotes = notes + } + + /** + * Add note to code line. + * + * @param num Line number + * @param note Note content + */ + fun addLineNote(num: Int, note: String) = addTask { + adapter.addLineNote(num, note) + } + /** * Update code content if view was built or, finally, build code view. * diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt new file mode 100644 index 0000000..e44ef2b --- /dev/null +++ b/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt @@ -0,0 +1,17 @@ +package io.github.kbiakov.codeview + +import android.content.Context +import android.widget.TextView + +class LineNoteView(context: Context?) : TextView(context) { + + companion object Factory { + fun create(context: Context, text: String, textColor: Int): LineNoteView { + val noteView = LineNoteView(context) + noteView.textSize = 12f + noteView.text = text + noteView.setTextColor(textColor) + return noteView + } + } +} diff --git a/codeview/src/main/res/layout/item_code_line.xml b/codeview/src/main/res/layout/item_code_line.xml index 9dc6622..8172e9a 100644 --- a/codeview/src/main/res/layout/item_code_line.xml +++ b/codeview/src/main/res/layout/item_code_line.xml @@ -2,7 +2,8 @@ + android:layout_height="wrap_content" + android:animateLayoutChanges="true"> + + diff --git a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java index be33f46..b02fd9a 100644 --- a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java +++ b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java @@ -4,7 +4,10 @@ import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; +import org.jetbrains.annotations.NotNull; + import io.github.kbiakov.codeview.CodeView; +import io.github.kbiakov.codeview.OnCodeLineClickListener; import io.github.kbiakov.codeview.highlight.ColorTheme; public class ListingsActivity extends AppCompatActivity { @@ -16,7 +19,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { //int myColor = ContextCompat.getColor(this, R.color.code_content_background); - CodeView codeView = (CodeView) findViewById(R.id.code_view); + final CodeView codeView = (CodeView) findViewById(R.id.code_view); // use chaining to build view codeView.highlightCode("js") @@ -25,8 +28,15 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { // do not use chaining for built view // (you can, but follow it should be performed sequentially) - codeView.setCodeContent(getString(R.string.listing_java)); + codeView.setCodeContent(getString(R.string.mark)); codeView.setColorTheme(ColorTheme.DEFAULT); codeView.highlightCode("java"); + + codeView.setCodeListener(new OnCodeLineClickListener() { + @Override + public void onCodeLineClicked(int n, @NotNull String line) { + codeView.addLineNote(n, line); + } + }); } } From 2fc9e0e7c1a499044b0429d83b8702fd423e97eb Mon Sep 17 00:00:00 2001 From: Kirill Biakov Date: Sat, 27 Aug 2016 00:54:46 +0300 Subject: [PATCH 3/6] Infinity line note views (not customizable) adding --- .../kbiakov/codeview/CodeContentAdapter.kt | 15 +++++++----- .../github/kbiakov/codeview/LineNoteView.kt | 23 ++++++++++++++++++- .../src/main/res/layout/item_code_line.xml | 10 ++++---- .../codeviewexample/ListingsActivity.java | 4 ++-- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt index f668700..fbcdd8b 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt @@ -234,9 +234,14 @@ class CodeContentAdapter : RecyclerView.Adapter { notes?.let { holder.llLineNotes.visibility = if (it.isNotEmpty()) View.VISIBLE else View.GONE + val noteBg = colorTheme.bgNum.color() + val noteColor = colorTheme.noteColor.color() + var isFirst = true + it.forEach { note -> - val noteView = LineNoteView.create(mContext, note, colorTheme.noteColor.color()) + val noteView = LineNoteView.create(mContext, note, isFirst, noteBg, noteColor) holder.llLineNotes.addView(noteView) + isFirst = false } } } @@ -247,14 +252,14 @@ class CodeContentAdapter : RecyclerView.Adapter { val isLast = position == itemCount - 1 if (isFirst || isLast) { - // itemView.layoutParams.height = dp8 * 4 + // holder.itemView.layoutParams.height = dp8 * 4 val topPadding = if (isFirst) dp8 else 0 val bottomPadding = if (isLast) dp8 else 0 holder.tvLineNum.setPadding(0, topPadding, 0, bottomPadding) holder.tvLineContent.setPadding(0, topPadding, 0, bottomPadding) } else { - // itemView.layoutParams.height = dp8 * 3 + // holder.itemView.layoutParams.height = dp8 * 3 holder.tvLineNum.setPadding(0, 0, 0, 0) holder.tvLineContent.setPadding(0, 0, 0, 0) @@ -271,7 +276,6 @@ class CodeContentAdapter : RecyclerView.Adapter { class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var tvLineNum: TextView var tvLineContent: TextView - var rlLineBlock: RelativeLayout var llLineNotes: LinearLayout var mItem: String? = null @@ -279,8 +283,7 @@ class CodeContentAdapter : RecyclerView.Adapter { init { tvLineNum = itemView.findViewById(R.id.tv_line_num) as TextView tvLineContent = itemView.findViewById(R.id.tv_line_content) as TextView - rlLineBlock = itemView.findViewById(R.id.rl_line_block) as RelativeLayout - llLineNotes = itemView.findViewById(R.id.ll_line_notes) as LinearLayout + llLineNotes = itemView.findViewById(R.id.ll_line_footer) as LinearLayout } override fun toString() = "${super.toString()} '$mItem'" diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt index e44ef2b..37bfb57 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt @@ -3,14 +3,35 @@ package io.github.kbiakov.codeview import android.content.Context import android.widget.TextView +/** + * Simple note view for code line. + * + * @author Kirill Biakov + */ class LineNoteView(context: Context?) : TextView(context) { companion object Factory { - fun create(context: Context, text: String, textColor: Int): LineNoteView { + /** + * Simple factory method to create note view. + * + * @param context Context + * @param text Note text + * @param isFirst If is first note + * @param bgColor Background color + * @param textColor Text Color + * @return Created line note view + */ + fun create(context: Context, text: String, isFirst: Boolean, + bgColor: Int, textColor: Int): LineNoteView { val noteView = LineNoteView(context) noteView.textSize = 12f noteView.text = text noteView.setTextColor(textColor) + noteView.setBackgroundColor(bgColor) + + val dp8 = dpToPx(context, 8) + noteView.setPadding(dpToPx(context, 48), if (isFirst) dp8 else 0, dp8, dp8) + return noteView } } diff --git a/codeview/src/main/res/layout/item_code_line.xml b/codeview/src/main/res/layout/item_code_line.xml index 8172e9a..c98ebee 100644 --- a/codeview/src/main/res/layout/item_code_line.xml +++ b/codeview/src/main/res/layout/item_code_line.xml @@ -2,13 +2,12 @@ + android:layout_height="wrap_content"> - + android:visibility="gone"/> diff --git a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java index b02fd9a..1313904 100644 --- a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java +++ b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java @@ -17,7 +17,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_listings); - //int myColor = ContextCompat.getColor(this, R.color.code_content_background); + // int myColor = ContextCompat.getColor(this, R.color.code_content_background); final CodeView codeView = (CodeView) findViewById(R.id.code_view); @@ -28,7 +28,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { // do not use chaining for built view // (you can, but follow it should be performed sequentially) - codeView.setCodeContent(getString(R.string.mark)); + codeView.setCodeContent(getString(R.string.listing_java)); codeView.setColorTheme(ColorTheme.DEFAULT); codeView.highlightCode("java"); From 3c017bfc5420f41007031c5d286d8de5160710dd Mon Sep 17 00:00:00 2001 From: Kirill Biakov Date: Sat, 27 Aug 2016 02:00:57 +0300 Subject: [PATCH 4/6] Added Monokai theme --- .../kbiakov/codeview/CodeContentAdapter.kt | 2 +- .../io/github/kbiakov/codeview/LineNoteView.kt | 2 +- .../codeview/highlight/CodeHighlighter.kt | 18 ++++++++++++++++++ .../src/main/res/layout/item_code_line.xml | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt index fbcdd8b..87899d4 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt @@ -215,11 +215,11 @@ class CodeContentAdapter : RecyclerView.Adapter { private fun setupLine(position: Int, line: String, holder: ViewHolder) { holder.tvLineContent.text = html(line) + holder.tvLineContent.setTextColor(colorTheme.noteColor.color()) if (!isFullShowing && position == MAX_SHORTCUT_LINES) { holder.tvLineNum.textSize = 10f holder.tvLineNum.text = mContext.getString(R.string.dots) - holder.tvLineContent.setTextColor(colorTheme.noteColor.color()) } else { holder.tvLineNum.textSize = 12f holder.tvLineNum.text = "${position + 1}" diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt index 37bfb57..ce83056 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt @@ -30,7 +30,7 @@ class LineNoteView(context: Context?) : TextView(context) { noteView.setBackgroundColor(bgColor) val dp8 = dpToPx(context, 8) - noteView.setPadding(dpToPx(context, 48), if (isFirst) dp8 else 0, dp8, dp8) + noteView.setPadding(dpToPx(context, 46), if (isFirst) dp8 else 0, dp8, dp8) return noteView } diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/highlight/CodeHighlighter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/highlight/CodeHighlighter.kt index ca8fcc9..54af59d 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/highlight/CodeHighlighter.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/highlight/CodeHighlighter.kt @@ -116,6 +116,24 @@ enum class ColorTheme( bgNum = 0xEEE8D5, noteColor = 0x657B83), + MONOKAI( + syntaxColors = SyntaxColors( + type = 0xA7E22E, + keyword = 0xFA2772, + literal = 0x66D9EE, + comment = 0x76715E, + string = 0xE6DB74, + punctuation = 0xC1C1C1, + plain = 0xF8F8F0, + tag = 0xF92672, + declaration = 0xFA2772, + attrName = 0xA6E22E, + attrValue = 0xE6DB74), + numColor = 0x48483E, + bgContent = 0x272822, + bgNum = 0x272822, + noteColor = 0xCFD0C2), + DEFAULT( numColor = 0x99A8B7, bgContent = 0xE9EDF4, diff --git a/codeview/src/main/res/layout/item_code_line.xml b/codeview/src/main/res/layout/item_code_line.xml index c98ebee..0185388 100644 --- a/codeview/src/main/res/layout/item_code_line.xml +++ b/codeview/src/main/res/layout/item_code_line.xml @@ -16,7 +16,7 @@ Date: Mon, 29 Aug 2016 18:31:49 +0300 Subject: [PATCH 5/6] Adapter customization (not finished yet) --- codeview/build.gradle | 10 +- .../io/github/kbiakov/codeview/CodeView.kt | 106 ++++++++++++------ .../java/io/github/kbiakov/codeview/Utils.kt | 10 +- .../AbstractCodeAdapter.kt} | 68 +++++------ .../codeview/adapters/CodeWithNotesAdapter.kt | 27 +++++ .../codeview/highlight/MonoFontCache.java | 4 +- .../{ => views}/BidirectionalScrollView.kt | 6 +- .../codeview/{ => views}/LineNoteView.kt | 13 +-- .../src/main/res/layout/layout_code_view.xml | 4 +- .../codeviewexample/ListingsActivity.java | 7 +- 10 files changed, 168 insertions(+), 87 deletions(-) rename codeview/src/main/java/io/github/kbiakov/codeview/{CodeContentAdapter.kt => adapters/AbstractCodeAdapter.kt} (82%) create mode 100644 codeview/src/main/java/io/github/kbiakov/codeview/adapters/CodeWithNotesAdapter.kt rename codeview/src/main/java/io/github/kbiakov/codeview/{ => views}/BidirectionalScrollView.kt (95%) rename codeview/src/main/java/io/github/kbiakov/codeview/{ => views}/LineNoteView.kt (63%) diff --git a/codeview/build.gradle b/codeview/build.gradle index 57383ae..90783af 100644 --- a/codeview/build.gradle +++ b/codeview/build.gradle @@ -26,11 +26,15 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:24.1.1' - compile 'com.android.support:recyclerview-v7:24.1.1' - compile 'com.github.twalcari:java-prettify:1.2.2' compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: '1.0.3' + + compile 'com.android.support:appcompat-v7:24.2.0' + compile 'com.android.support:recyclerview-v7:24.2.0' + compile 'com.github.twalcari:java-prettify:1.2.2' } repositories { mavenCentral() } +buildscript { +} diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt index d1b3fa2..9783f8c 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt @@ -3,7 +3,6 @@ package io.github.kbiakov.codeview import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.content.Context -import android.os.Handler import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.util.AttributeSet @@ -11,10 +10,13 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewPropertyAnimator import android.widget.RelativeLayout +import io.github.kbiakov.codeview.adapters.AbstractCodeAdapter +import io.github.kbiakov.codeview.Thread.delayed +import io.github.kbiakov.codeview.adapters.CodeWithNotesAdapter import io.github.kbiakov.codeview.highlight.ColorTheme import io.github.kbiakov.codeview.highlight.ColorThemeData -import io.github.kbiakov.codeview.highlight.color import java.util.* +import kotlin.reflect.KClass /** * @class CodeView @@ -33,7 +35,7 @@ import java.util.* * * @author Kirill Biakov */ -class CodeView : RelativeLayout { +class CodeView : RelativeLayout { private val vPlaceholder: View private val vShadowRight: View @@ -56,6 +58,9 @@ class CodeView : RelativeLayout { */ private var state: ViewState + /** + * Default constructor. + */ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater inflater.inflate(R.layout.layout_code_view, this, true) @@ -69,13 +74,13 @@ class CodeView : RelativeLayout { rvCodeContent.layoutManager = LinearLayoutManager(context) rvCodeContent.isNestedScrollingEnabled = true - tasks = LinkedList() - state = ViewState.BUILD + + tasks = LinkedList() } /** - * Code view states. + * Code view state to control build flow. */ enum class ViewState { BUILD, @@ -84,24 +89,64 @@ class CodeView : RelativeLayout { } /** - * Public getter for accessing view state. - * It may be useful if code view state is unknown. - * If code view was built it is not safe to use operations chaining. + * Public getters for checking view state. + * May be useful when code view state is unknown. + * If view was built it is unsafe to use operations chaining. + * + * @return Result of state check */ - fun getState() = state + fun isBuilding() = state == ViewState.BUILD + fun isPrepared() = state == ViewState.PREPARE + fun isPresented() = state == ViewState.PRESENTED + + /** + * TODO + */ + private var AdapterClass: KClass>? = null + + fun registerAdapterClass(adapterClass: KClass>) { + if (state == ViewState.BUILD) + AdapterClass = adapterClass + else throw RuntimeException("CodeView is already registered with " + + "${AdapterClass?.simpleName} class name. Please, check the build flow.") + } + + fun registerAdapterClass(adapterClass: Class>) = + registerAdapterClass(adapterClass.kotlin) /** * Accessor/mutator to reduce frequently used actions. */ - var adapter: CodeContentAdapter + private var adapter: AbstractCodeAdapter get() { - return rvCodeContent.adapter as CodeContentAdapter + return rvCodeContent.adapter as AbstractCodeAdapter } set(adapter) { rvCodeContent.adapter = adapter state = ViewState.PRESENTED } + /** + * TODO + */ + private fun createAdapter(content: String) = + (AdapterClass ?: CodeWithNotesAdapter::class) + .constructors + .first() + .call(context, content) + + /** + * TODO + */ + private fun setupInitAdapter(content: String) { + try { + rvCodeContent.adapter = createAdapter(content) + } catch (e: IllegalArgumentException) { + throw IllegalArgumentException("You're registered ${AdapterClass?.simpleName}, " + + "but default constructor with 2 params (context & code content) not found.") + } + } + // - Build processor /** @@ -111,12 +156,12 @@ class CodeView : RelativeLayout { * * @param task Task to process */ - private fun addTask(task: () -> Unit): CodeView { + private fun addTask(task: () -> Unit): CodeView { when (state) { ViewState.BUILD -> tasks.add(task) ViewState.PREPARE -> - Thread.delayed(task) + delayed(body = task) ViewState.PRESENTED -> task() } @@ -193,22 +238,22 @@ class CodeView : RelativeLayout { } /** - * Add notes to code snippet. + * Add entities to code snippet as footer. * - * @param notes Map of notes (line number -> list of notes) + * @param entities Map of entities (line number -> list of entities) */ - fun addLineNotes(notes: HashMap>) = addTask { - adapter.lineNotes = notes + fun addFooterEntities(entities: HashMap>) = addTask { + adapter.footerEntities = entities } /** - * Add note to code line. + * Add footer entity to code line. * * @param num Line number - * @param note Note content + * @param entity Entity content */ - fun addLineNote(num: Int, note: String) = addTask { - adapter.addLineNote(num, note) + fun addFooterEntity(num: Int, entity: T) = addTask { + adapter.addFooterEntity(num, entity) } /** @@ -221,7 +266,7 @@ class CodeView : RelativeLayout { ViewState.BUILD -> build(content) ViewState.PREPARE -> - Thread.delayed { + delayed { update(content) } ViewState.PRESENTED -> @@ -243,8 +288,8 @@ class CodeView : RelativeLayout { measurePlaceholder(linesCount) state = ViewState.PREPARE - Thread.delayed { - rvCodeContent.adapter = CodeContentAdapter(context, content) + delayed { + setupInitAdapter(content) processBuildTasks() setupShadows() hidePlaceholder() @@ -288,8 +333,8 @@ class CodeView : RelativeLayout { val height = linesCount * lineHeight + padding - vPlaceholder.layoutParams = RelativeLayout.LayoutParams( - RelativeLayout.LayoutParams.MATCH_PARENT, height) + vPlaceholder.layoutParams = LayoutParams( + LayoutParams.MATCH_PARENT, height) vPlaceholder.visibility = View.VISIBLE } @@ -318,13 +363,6 @@ interface OnCodeLineClickListener { fun onCodeLineClicked(n: Int, line: String) } -/** - * Extension for delayed block call. - * - * @param body Operation body - */ -fun Thread.delayed(body: () -> Unit) = Handler().postDelayed(body, 150) - /** * More readable form for animation listener (hi, iOS & Cocoa Touch!). * diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/Utils.kt b/codeview/src/main/java/io/github/kbiakov/codeview/Utils.kt index ade5e3b..bfff99b 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/Utils.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/Utils.kt @@ -43,7 +43,7 @@ fun extractLines(source: String) = listOf(*source.split("\n").toTypedArray()) * @param content Source * @return Spanned HTML string */ -@Suppress("DEPRECATION") +@Suppress("deprecation") fun html(content: String): Spanned = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) Html.fromHtml(content, Html.FROM_HTML_MODE_LEGACY) @@ -69,6 +69,14 @@ object Thread { Handler(Looper.getMainLooper()).post(body) } + /** + * Delayed block call. + * + * @param body Operation body + * @param delayMs Delay in m + */ + fun delayed(delayMs: Long = 150, body: () -> Unit) = Handler().postDelayed(body, delayMs) + // - Extensions for block manipulations fun (() -> Unit).async(isAsync: Boolean = true) { diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/adapters/AbstractCodeAdapter.kt similarity index 82% rename from codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt rename to codeview/src/main/java/io/github/kbiakov/codeview/adapters/AbstractCodeAdapter.kt index 87899d4..c07b057 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeContentAdapter.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/adapters/AbstractCodeAdapter.kt @@ -1,4 +1,4 @@ -package io.github.kbiakov.codeview +package io.github.kbiakov.codeview.adapters import android.content.Context import android.support.v7.widget.RecyclerView @@ -6,23 +6,24 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.LinearLayout -import android.widget.RelativeLayout import android.widget.TextView +import io.github.kbiakov.codeview.* import io.github.kbiakov.codeview.classifier.CodeProcessor import io.github.kbiakov.codeview.highlight.* import io.github.kbiakov.codeview.Thread.async import io.github.kbiakov.codeview.Thread.ui import io.github.kbiakov.codeview.classifier.CodeClassifier +import io.github.kbiakov.codeview.OnCodeLineClickListener import java.util.* /** - * @class CodeContentAdapter + * @class AbstractCodeAdapter * * Adapter for code view. * * @author Kirill Biakov */ -class CodeContentAdapter : RecyclerView.Adapter { +abstract class AbstractCodeAdapter : RecyclerView.Adapter { private val mContext: Context private var mContent: String @@ -34,28 +35,28 @@ class CodeContentAdapter : RecyclerView.Adapter { internal var codeListener: OnCodeLineClickListener? - internal var lineNotes: HashMap> - set(lineNotes) { - field = lineNotes - notifyDataSetChanged() - } - internal var colorTheme: ColorThemeData set(colorTheme) { field = colorTheme notifyDataSetChanged() } + internal var footerEntities: HashMap> + set(footerEntities) { + field = footerEntities + notifyDataSetChanged() + } + init { mLines = ArrayList() mDroppedLines = null isFullShowing = true - lineNotes = HashMap() colorTheme = ColorTheme.SOLARIZED_LIGHT.with() + footerEntities = HashMap() } /** - * Adapter constructor + * Adapter constructor. * * @param content Context * @param content Code content @@ -116,14 +117,14 @@ class CodeContentAdapter : RecyclerView.Adapter { } /** - * Add note to code line. + * Add footer entity for code line. * * @param num Line number - * @param note Note content + * @param entity Footer entity */ - fun addLineNote(num: Int, note: String) { - val notes = lineNotes[num] ?: ArrayList() - lineNotes.put(num, notes + note) + fun addFooterEntity(num: Int, entity: T) { + val notes = footerEntities[num] ?: ArrayList() + footerEntities.put(num, notes + entity) notifyDataSetChanged() } @@ -174,7 +175,7 @@ class CodeContentAdapter : RecyclerView.Adapter { updateContent(lines, onReady) } - private fun showAllBottomNote() = mContext.getString(R.string.show_all) + internal fun showAllBottomNote() = mContext.getString(R.string.show_all) private fun monoTypeface() = MonoFontCache.getInstance(mContext).typeface @@ -205,7 +206,7 @@ class CodeContentAdapter : RecyclerView.Adapter { } setupLine(position, codeLine, holder) - displayLineNotes(position, holder) + displayFooterEntities(position, holder) addExtraPadding(position, holder) } @@ -226,26 +227,29 @@ class CodeContentAdapter : RecyclerView.Adapter { } } - private fun displayLineNotes(position: Int, holder: ViewHolder) { - val notes = lineNotes[position] + private fun displayFooterEntities(position: Int, holder: ViewHolder) { + val entityList = footerEntities[position] - holder.llLineNotes.removeAllViews() + holder.llLineFooter.removeAllViews() - notes?.let { - holder.llLineNotes.visibility = if (it.isNotEmpty()) View.VISIBLE else View.GONE + entityList?.let { + holder.llLineFooter.visibility = if (it.isNotEmpty()) View.VISIBLE else View.GONE - val noteBg = colorTheme.bgNum.color() - val noteColor = colorTheme.noteColor.color() var isFirst = true - it.forEach { note -> - val noteView = LineNoteView.create(mContext, note, isFirst, noteBg, noteColor) - holder.llLineNotes.addView(noteView) + it.forEach { entity -> + val footerView = createFooter(mContext, entity) + val dp8 = dpToPx(mContext, 8) + footerView.setPadding(dpToPx(mContext, 46), if (isFirst) dp8 else 0, dp8, dp8) + + holder.llLineFooter.addView(footerView) isFirst = false } } } + abstract fun createFooter(context: Context, entity: T): View + private fun addExtraPadding(position: Int, holder: ViewHolder) { val dp8 = dpToPx(mContext, 8) val isFirst = position == 0 @@ -270,20 +274,20 @@ class CodeContentAdapter : RecyclerView.Adapter { } companion object { - private const val MAX_SHORTCUT_LINES = 6 + internal const val MAX_SHORTCUT_LINES = 6 } class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { var tvLineNum: TextView var tvLineContent: TextView - var llLineNotes: LinearLayout + var llLineFooter: LinearLayout var mItem: String? = null init { tvLineNum = itemView.findViewById(R.id.tv_line_num) as TextView tvLineContent = itemView.findViewById(R.id.tv_line_content) as TextView - llLineNotes = itemView.findViewById(R.id.ll_line_footer) as LinearLayout + llLineFooter = itemView.findViewById(R.id.ll_line_footer) as LinearLayout } override fun toString() = "${super.toString()} '$mItem'" diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/adapters/CodeWithNotesAdapter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/adapters/CodeWithNotesAdapter.kt new file mode 100644 index 0000000..95a16ac --- /dev/null +++ b/codeview/src/main/java/io/github/kbiakov/codeview/adapters/CodeWithNotesAdapter.kt @@ -0,0 +1,27 @@ +package io.github.kbiakov.codeview.adapters + +import android.content.Context +import io.github.kbiakov.codeview.highlight.color +import io.github.kbiakov.codeview.views.LineNoteView + +/** + * + */ +class CodeWithNotesAdapter : AbstractCodeAdapter { + /** + * Default constructor. + */ + constructor(context: Context, content: String) : super(context, content) + + /** + * Add note to code line. + * + * @param num Line number + * @param entity Note content + */ + override fun createFooter(context: Context, entity: String) = + LineNoteView.create(context, + noteText = entity, + bgColor = colorTheme.bgNum.color(), + textColor = colorTheme.noteColor.color()) +} diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/highlight/MonoFontCache.java b/codeview/src/main/java/io/github/kbiakov/codeview/highlight/MonoFontCache.java index fc49790..50cd2d4 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/highlight/MonoFontCache.java +++ b/codeview/src/main/java/io/github/kbiakov/codeview/highlight/MonoFontCache.java @@ -3,12 +3,14 @@ import android.content.Context; import android.graphics.Typeface; +import io.github.kbiakov.codeview.adapters.AbstractCodeAdapter; + /** * @class MonoFontCache * * Simple font cache. * - * @see io.github.kbiakov.codeview.CodeContentAdapter + * @see AbstractCodeAdapter * @author Kirill Biakov */ public class MonoFontCache { diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/BidirectionalScrollView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/views/BidirectionalScrollView.kt similarity index 95% rename from codeview/src/main/java/io/github/kbiakov/codeview/BidirectionalScrollView.kt rename to codeview/src/main/java/io/github/kbiakov/codeview/views/BidirectionalScrollView.kt index 373b0a6..6eedfb1 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/BidirectionalScrollView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/views/BidirectionalScrollView.kt @@ -1,12 +1,12 @@ -package io.github.kbiakov.codeview +package io.github.kbiakov.codeview.views import android.content.Context import android.util.AttributeSet import android.view.MotionEvent import android.view.View import android.view.View.MeasureSpec.makeMeasureSpec -import android.view.ViewGroup import android.widget.HorizontalScrollView +import io.github.kbiakov.codeview.dpToPx /** * @class BidirectionalScrollView @@ -77,7 +77,7 @@ class BidirectionalScrollView : HorizontalScrollView { override fun measureChildWithMargins(child: View, parentWidthMeasureSpec: Int, widthUsed: Int, parentHeightMeasureSpec: Int, heightUsed: Int) { - val params = child.layoutParams as ViewGroup.MarginLayoutParams + val params = child.layoutParams as MarginLayoutParams val childWidthMeasureSpec = makeMeasureSpec( params.leftMargin + params.rightMargin, MeasureSpec.UNSPECIFIED) diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/views/LineNoteView.kt similarity index 63% rename from codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt rename to codeview/src/main/java/io/github/kbiakov/codeview/views/LineNoteView.kt index ce83056..e097a52 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/LineNoteView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/views/LineNoteView.kt @@ -1,4 +1,4 @@ -package io.github.kbiakov.codeview +package io.github.kbiakov.codeview.views import android.content.Context import android.widget.TextView @@ -15,23 +15,18 @@ class LineNoteView(context: Context?) : TextView(context) { * Simple factory method to create note view. * * @param context Context - * @param text Note text - * @param isFirst If is first note + * @param noteText Note text * @param bgColor Background color * @param textColor Text Color * @return Created line note view */ - fun create(context: Context, text: String, isFirst: Boolean, - bgColor: Int, textColor: Int): LineNoteView { + fun create(context: Context, noteText: String, bgColor: Int, textColor: Int): LineNoteView { val noteView = LineNoteView(context) noteView.textSize = 12f - noteView.text = text + noteView.text = noteText noteView.setTextColor(textColor) noteView.setBackgroundColor(bgColor) - val dp8 = dpToPx(context, 8) - noteView.setPadding(dpToPx(context, 46), if (isFirst) dp8 else 0, dp8, dp8) - return noteView } } diff --git a/codeview/src/main/res/layout/layout_code_view.xml b/codeview/src/main/res/layout/layout_code_view.xml index ee66263..7407af2 100644 --- a/codeview/src/main/res/layout/layout_code_view.xml +++ b/codeview/src/main/res/layout/layout_code_view.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - - + Date: Tue, 30 Aug 2016 00:12:01 +0300 Subject: [PATCH 6/6] Finished adapter customization, added ability to put custom footer view --- .../io/github/kbiakov/codeview/CodeView.kt | 77 ++++--------------- .../codeview/adapters/AbstractCodeAdapter.kt | 35 +++++---- .../codeview/adapters/CodeWithNotesAdapter.kt | 10 ++- .../kbiakov/codeview/views/LineNoteView.kt | 10 ++- .../codeviewexample/CustomAdapter.java | 44 +++++++++++ .../codeviewexample/ListingsActivity.java | 39 ++++++++-- example/src/main/res/layout/custom_footer.xml | 22 ++++++ 7 files changed, 144 insertions(+), 93 deletions(-) create mode 100644 example/src/main/java/io/github/kbiakov/codeviewexample/CustomAdapter.java create mode 100644 example/src/main/res/layout/custom_footer.xml diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt index 9783f8c..3887a91 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/CodeView.kt @@ -16,7 +16,6 @@ import io.github.kbiakov.codeview.adapters.CodeWithNotesAdapter import io.github.kbiakov.codeview.highlight.ColorTheme import io.github.kbiakov.codeview.highlight.ColorThemeData import java.util.* -import kotlin.reflect.KClass /** * @class CodeView @@ -35,7 +34,7 @@ import kotlin.reflect.KClass * * @author Kirill Biakov */ -class CodeView : RelativeLayout { +class CodeView : RelativeLayout { private val vPlaceholder: View private val vShadowRight: View @@ -57,6 +56,11 @@ class CodeView : RelativeLayout { * (and awaiting for build) or view was built & code is presented. */ private var state: ViewState + set(newState) { + if (newState == ViewState.PRESENTED) + hidePlaceholder() + field = newState + } /** * Default constructor. @@ -99,53 +103,19 @@ class CodeView : RelativeLayout { fun isPrepared() = state == ViewState.PREPARE fun isPresented() = state == ViewState.PRESENTED - /** - * TODO - */ - private var AdapterClass: KClass>? = null - - fun registerAdapterClass(adapterClass: KClass>) { - if (state == ViewState.BUILD) - AdapterClass = adapterClass - else throw RuntimeException("CodeView is already registered with " + - "${AdapterClass?.simpleName} class name. Please, check the build flow.") - } - - fun registerAdapterClass(adapterClass: Class>) = - registerAdapterClass(adapterClass.kotlin) - /** * Accessor/mutator to reduce frequently used actions. */ - private var adapter: AbstractCodeAdapter + var adapter: AbstractCodeAdapter<*> get() { - return rvCodeContent.adapter as AbstractCodeAdapter + return rvCodeContent.adapter as AbstractCodeAdapter<*> } set(adapter) { - rvCodeContent.adapter = adapter - state = ViewState.PRESENTED - } - - /** - * TODO - */ - private fun createAdapter(content: String) = - (AdapterClass ?: CodeWithNotesAdapter::class) - .constructors - .first() - .call(context, content) - - /** - * TODO - */ - private fun setupInitAdapter(content: String) { - try { - rvCodeContent.adapter = createAdapter(content) - } catch (e: IllegalArgumentException) { - throw IllegalArgumentException("You're registered ${AdapterClass?.simpleName}, " + - "but default constructor with 2 params (context & code content) not found.") + delayed { // to prevent UI overhead & initialization inconsistency + rvCodeContent.adapter = adapter + state = ViewState.PRESENTED + } } - } // - Build processor @@ -156,7 +126,7 @@ class CodeView : RelativeLayout { * * @param task Task to process */ - private fun addTask(task: () -> Unit): CodeView { + private fun addTask(task: () -> Unit): CodeView { when (state) { ViewState.BUILD -> tasks.add(task) @@ -237,25 +207,6 @@ class CodeView : RelativeLayout { vShadowBottomContent.visibility = visibility } - /** - * Add entities to code snippet as footer. - * - * @param entities Map of entities (line number -> list of entities) - */ - fun addFooterEntities(entities: HashMap>) = addTask { - adapter.footerEntities = entities - } - - /** - * Add footer entity to code line. - * - * @param num Line number - * @param entity Entity content - */ - fun addFooterEntity(num: Int, entity: T) = addTask { - adapter.addFooterEntity(num, entity) - } - /** * Update code content if view was built or, finally, build code view. * @@ -289,7 +240,7 @@ class CodeView : RelativeLayout { state = ViewState.PREPARE delayed { - setupInitAdapter(content) + rvCodeContent.adapter = CodeWithNotesAdapter(context, content) processBuildTasks() setupShadows() hidePlaceholder() diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/adapters/AbstractCodeAdapter.kt b/codeview/src/main/java/io/github/kbiakov/codeview/adapters/AbstractCodeAdapter.kt index c07b057..34bbe04 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/adapters/AbstractCodeAdapter.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/adapters/AbstractCodeAdapter.kt @@ -19,7 +19,7 @@ import java.util.* /** * @class AbstractCodeAdapter * - * Adapter for code view. + * Basic adapter for code view. * * @author Kirill Biakov */ @@ -103,7 +103,7 @@ abstract class AbstractCodeAdapter : RecyclerView.Adapter : RecyclerView.Adapter, onUpdated: () -> Unit) { @@ -175,7 +184,7 @@ abstract class AbstractCodeAdapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter : RecyclerView.Adapter { /** @@ -14,14 +18,14 @@ class CodeWithNotesAdapter : AbstractCodeAdapter { constructor(context: Context, content: String) : super(context, content) /** - * Add note to code line. + * Create footer view. * - * @param num Line number + * @param context Context * @param entity Note content */ override fun createFooter(context: Context, entity: String) = LineNoteView.create(context, - noteText = entity, + text = entity, bgColor = colorTheme.bgNum.color(), textColor = colorTheme.noteColor.color()) } diff --git a/codeview/src/main/java/io/github/kbiakov/codeview/views/LineNoteView.kt b/codeview/src/main/java/io/github/kbiakov/codeview/views/LineNoteView.kt index e097a52..609d294 100644 --- a/codeview/src/main/java/io/github/kbiakov/codeview/views/LineNoteView.kt +++ b/codeview/src/main/java/io/github/kbiakov/codeview/views/LineNoteView.kt @@ -4,7 +4,9 @@ import android.content.Context import android.widget.TextView /** - * Simple note view for code line. + * @class LineNoteView + * + * Note view for code line. Default footer view. * * @author Kirill Biakov */ @@ -15,15 +17,15 @@ class LineNoteView(context: Context?) : TextView(context) { * Simple factory method to create note view. * * @param context Context - * @param noteText Note text + * @param text Note text * @param bgColor Background color * @param textColor Text Color * @return Created line note view */ - fun create(context: Context, noteText: String, bgColor: Int, textColor: Int): LineNoteView { + fun create(context: Context, text: String, bgColor: Int, textColor: Int): LineNoteView { val noteView = LineNoteView(context) noteView.textSize = 12f - noteView.text = noteText + noteView.text = text noteView.setTextColor(textColor) noteView.setBackgroundColor(bgColor) diff --git a/example/src/main/java/io/github/kbiakov/codeviewexample/CustomAdapter.java b/example/src/main/java/io/github/kbiakov/codeviewexample/CustomAdapter.java new file mode 100644 index 0000000..4336de2 --- /dev/null +++ b/example/src/main/java/io/github/kbiakov/codeviewexample/CustomAdapter.java @@ -0,0 +1,44 @@ +package io.github.kbiakov.codeviewexample; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import org.jetbrains.annotations.NotNull; + +import io.github.kbiakov.codeview.adapters.AbstractCodeAdapter; + +public class CustomAdapter extends AbstractCodeAdapter { + + public CustomAdapter(@NotNull Context context, @NotNull String content) { + super(context, content, true, 10, context.getString(R.string.show_all), null); + } + + @NotNull + @Override + public View createFooter(@NotNull Context context, CustomModel entity) { + View footerView = LayoutInflater.from(context).inflate(R.layout.custom_footer, null); + ((TextView) footerView.findViewById(R.id.tv_footer_title)).setText(entity.firstName); + ((TextView) footerView.findViewById(R.id.tv_footer_description)).setText(entity.lastName); + return footerView; + } + + public static class CustomModel { + private String firstName; + private String lastName; + + public CustomModel(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + } +} diff --git a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java index cdd5bed..548eaa9 100644 --- a/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java +++ b/example/src/main/java/io/github/kbiakov/codeviewexample/ListingsActivity.java @@ -2,7 +2,9 @@ import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; +import android.util.Log; import org.jetbrains.annotations.NotNull; @@ -18,27 +20,48 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_listings); - // int myColor = ContextCompat.getColor(this, R.color.code_content_background); + int myColor = ContextCompat.getColor(this, R.color.code_num); - final CodeView codeView = (CodeView) findViewById(R.id.code_view); + CodeView codeView = (CodeView) findViewById(R.id.code_view); - codeView.registerAdapterClass(CodeWithNotesAdapter.class); + /** + * 1: Default adapter with chaining build flow + */ - // use chaining to build view + // use chaining to build view with default adapter codeView.highlightCode("js") - .setColorTheme(ColorTheme.SOLARIZED_LIGHT) + .setColorTheme(ColorTheme.DEFAULT.withBgContent(myColor)) .setCodeContent(getString(R.string.listing_js)); + /** + * 2: Updating built view + */ + // do not use chaining for built view - // (you can, but follow it should be performed sequentially) + // (you can, but it should be performed sequentially) codeView.setCodeContent(getString(R.string.listing_java)); - codeView.setColorTheme(ColorTheme.DEFAULT); + codeView.setColorTheme(ColorTheme.SOLARIZED_LIGHT); codeView.highlightCode("java"); + codeView.setCodeListener(new OnCodeLineClickListener() { + @Override + public void onCodeLineClicked(int n, @NotNull String line) { + Log.i("ListingsActivity", "On " + (n + 1) + " line clicked"); + } + }); + + /** + * 3: Custom adapter with footer views + */ + + final CustomAdapter adapter = new CustomAdapter(this, getString(R.string.listing_py)); + codeView.setAdapter(adapter); + codeView.setColorTheme(ColorTheme.MONOKAI); + codeView.highlightCode("python"); codeView.setCodeListener(new OnCodeLineClickListener() { @Override public void onCodeLineClicked(int n, @NotNull String line) { - codeView.addFooterEntity(n, line); + adapter.addFooterEntity(n, new CustomAdapter.CustomModel("Line " + (n + 1), line)); } }); } diff --git a/example/src/main/res/layout/custom_footer.xml b/example/src/main/res/layout/custom_footer.xml new file mode 100644 index 0000000..1ead22a --- /dev/null +++ b/example/src/main/res/layout/custom_footer.xml @@ -0,0 +1,22 @@ + + + + + + + +