Skip to content

Commit

Permalink
* added new filters to viewer
Browse files Browse the repository at this point in the history
* adjusted viewer look
  • Loading branch information
MFlisar committed Jun 9, 2021
1 parent d305e0b commit 0f09866
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 79 deletions.
5 changes: 5 additions & 0 deletions demo/src/main/java/com/michaelflisar/lumberjack/demo/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import android.app.Application

class App : Application() {

companion object {
// just for the demo - a global "setting" value
var darkTheme: Boolean = false
}

override fun onCreate() {
super.onCreate()
LogHelper.init(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.michaelflisar.lumberjack.demo

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.lifecycle.lifecycleScope
import com.michaelflisar.lumberjack.L
import com.michaelflisar.lumberjack.demo.databinding.ActivityMainBinding
Expand All @@ -16,6 +17,7 @@ class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
updateTheme()
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

Expand Down Expand Up @@ -59,12 +61,25 @@ class MainActivity : AppCompatActivity() {
binding.btShowLogFile.setOnClickListener {
L.showLog(this, LogHelper.FILE_LOGGING_SETUP)
}
binding.cbDarkTheme.apply {
isChecked = App.darkTheme
setOnCheckedChangeListener { _, isChecked ->
if (isChecked != App.darkTheme) {
App.darkTheme = isChecked
updateTheme()
}
}
}

for (i in 0..500) {
L.d { "Test $i" }
}
}

private fun updateTheme() {
AppCompatDelegate.setDefaultNightMode(if (App.darkTheme) AppCompatDelegate.MODE_NIGHT_YES else AppCompatDelegate.MODE_NIGHT_NO)
}

private class TestException(msg: String) : Throwable(msg) {
override fun toString(): String {
return message!!
Expand Down
14 changes: 12 additions & 2 deletions demo/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@
android:layout_height="match_parent"
tools:context=".MainActivity">

<CheckBox
android:id="@+id/cbDarkTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:text="Use dark theme"
tools:ignore="HardcodedText"/>

<Button
android:id="@+id/btSendFeedback"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send log file via mail"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cbDarkTheme"
tools:ignore="HardcodedText" />

<Button
Expand Down
2 changes: 1 addition & 1 deletion demo/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<resources>

<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">

<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,29 @@ package com.michaelflisar.lumberjack
import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.os.Build
import android.text.Spannable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
import android.text.style.StyleSpan
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.core.text.toSpannable
import androidx.recyclerview.widget.RecyclerView
import com.michaelflisar.lumberjack.viewer.databinding.LogItemRowBinding

internal class LogAdapter(
context: Context,
var items: List<Item>,
var filter: String
) : RecyclerView.Adapter<LogAdapter.ViewHolder>() {

companion object {
@ColorInt
private fun getColorFromAttr(
context: Context,
@AttrRes attrColor: Int,
typedValue: TypedValue = TypedValue(),
resolveRefs: Boolean = true
): Int {
context.theme.resolveAttribute(attrColor, typedValue, resolveRefs)
return typedValue.data
}
}
private val bgColor1: Int = if (context.isCurrentThemeDark()) Color.BLACK else Color.WHITE
private val bgColor2: Int = if (context.isCurrentThemeDark()) Color.DKGRAY else Color.LTGRAY
private val highlightColor: Int =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) context.getColorFromAttr(android.R.attr.colorPrimary) else Color.BLUE
private val textColor: Int = TextView(context).textColors.defaultColor

fun update(items: List<Item>, filter: String) {
this.items = items
Expand All @@ -47,10 +39,8 @@ internal class LogAdapter(

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = LogItemRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
if (viewType == 1) {
binding.root.setBackgroundColor(Color.parseColor("#11000000"))
}
return ViewHolder(binding)
binding.root.setBackgroundColor(if (viewType == 0) bgColor1 else bgColor2)
return ViewHolder(binding, highlightColor, textColor)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
Expand All @@ -65,23 +55,18 @@ internal class LogAdapter(
override fun getItemCount(): Int = items.size

class ViewHolder(
private val binding: LogItemRowBinding
private val binding: LogItemRowBinding,
private val highlightColor: Int,
private val textColor: Int
) : RecyclerView.ViewHolder(binding.root) {

private val highlightColor by lazy {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
getColorFromAttr(binding.root.context, android.R.attr.colorPrimary)
} else {
Color.BLUE
}
}

fun bind(item: Item, filter: String, pos: Int) {
binding.tvNumber.text = "${item.row + 1}"
binding.tvType.setTextColor(item.level.getTitleColor(binding.root.context))
binding.tvType.setTextColor(item.level.getTitleColor(textColor))
binding.tvType.text = item.level.name
binding.tvDate.text = item.date
binding.tvRow.setTextColor(item.level.getTextColor(binding.root.context))
binding.tvRow.setTextColor(item.level.getTextColor(textColor))
binding.tvRow.text = getHighlightedText(item.text, filter, true)
}

Expand Down Expand Up @@ -130,35 +115,27 @@ internal class LogAdapter(

class Item(val row: Int, val text: String, val level: Level, val date: String?) {

enum class Level(val useDefaultTextColor: Boolean, private val color: Int) {
TRACE(true, -1),
DEBUG(true, -1),
INFO(true, -1),
WARN(false, Color.parseColor("#FFA500") /* orange */),
ERROR(false, Color.RED),
UNKNOWN(false, android.R.color.transparent)
enum class Level(val level: Int, val useDefaultTextColor: Boolean, private val color: Int) {
TRACE(0, true, -1),
DEBUG(1, true, -1),
INFO(2, true, -1),
WARN(3, false, Color.parseColor("#FFA500") /* orange */),
ERROR(4, false, Color.RED),
UNKNOWN(-1, false, android.R.color.transparent)
;

private var c: Int? = null
private var c2: Int? = null

fun getTitleColor(context: Context) : Int {
if (c == null) {
c = if (useDefaultTextColor) {
TextView(context).textColors.defaultColor
} else color
}
return c!!
fun getTitleColor(textColor: Int): Int {
return if (useDefaultTextColor) textColor else color
}

fun getTextColor(context: Context) : Int {
val c = getTitleColor(context)
if (c2 == null) {
c2 = if (!useDefaultTextColor && getTitleColor(context) == android.R.color.transparent)
TextView(context).textColors.defaultColor
else c
}
return c2!!
fun getTextColor(textColor: Int): Int {
val c = getTitleColor(textColor)
return if (!useDefaultTextColor && c == android.R.color.transparent)
textColor
else c
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.michaelflisar.lumberjack

import android.content.Context
import android.graphics.Color
import android.util.TypedValue
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt

@ColorInt
internal fun Context.getColorFromAttr(
@AttrRes attrColor: Int,
typedValue: TypedValue = TypedValue(),
resolveRefs: Boolean = true
): Int {
theme.resolveAttribute(attrColor, typedValue, resolveRefs)
return typedValue.data
}

internal fun Context.isCurrentThemeDark(): Boolean {
val color = resolve(android.R.attr.colorBackground)
val darkness =
1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255
return darkness > 0.5
}

private fun Context.resolve(attrId: Int): Int {
val typedValue = TypedValue()
theme.resolveAttribute(attrId, typedValue, true)
return typedValue.data
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import java.io.File

object LumberjackViewer : ILumberjackViewActivityProvider {

val FILE = "FILE"
const val FILE = "FILE"

fun show(context: Context, file: File) {
context.startActivity(createIntent(context, file))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.michaelflisar.lumberjack

import android.R
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import androidx.appcompat.app.AppCompatActivity
import androidx.core.widget.doAfterTextChanged
import androidx.lifecycle.lifecycleScope
Expand Down Expand Up @@ -59,11 +63,11 @@ internal class LumberjackViewerActivity : AppCompatActivity() {

logs = allLogs

adapter = LogAdapter(logs, "")
adapter = LogAdapter(this@LumberjackViewerActivity, logs, "")
loading = false
withContext(Dispatchers.Main) {
binding.rvLogs.adapter = adapter
updateFilter(binding.etFilter.text.toString(), true)
updateFilter(true)
}
}
}
Expand All @@ -76,14 +80,14 @@ internal class LumberjackViewerActivity : AppCompatActivity() {
// we try to get log level from default file logging format
// e.g. 2000-01-01 00:00:00.000 INFO Some log
// => 23 chars (including 1 space) + 2nd space + TAG + 3rd space + rest
if (logEntry.count { it == ' ' } > 3)
{
if (logEntry.count { it == ' ' } > 3) {
val ind1 = logEntry.indexOf(' ')
val ind2 = logEntry.indexOf(' ', ind1 + 1)
val ind3 = logEntry.indexOf(' ', ind2 + 1)
val levelString = logEntry.substring(ind2, ind3).trim()
date = logEntry.substring(0, ind2).trim()
level = LogAdapter.Item.Level.values().find { it.name == levelString } ?: LogAdapter.Item.Level.UNKNOWN
level = LogAdapter.Item.Level.values().find { it.name == levelString }
?: LogAdapter.Item.Level.UNKNOWN
}
return LogAdapter.Item(existingEntry, logEntry, level, date)
}
Expand All @@ -92,27 +96,57 @@ internal class LumberjackViewerActivity : AppCompatActivity() {

private fun initFilter() {
binding.etFilter.doAfterTextChanged {
updateFilter(it?.toString() ?: "", false)
updateFilter(false)
}

val items = mutableListOf("ALL")
items.addAll(LogAdapter.Item.Level.values().filter { it.level != -1 }.map { it.name })
binding.spLevel.adapter = ArrayAdapter(this, R.layout.simple_spinner_item, items).apply {
setDropDownViewResource(R.layout.simple_spinner_dropdown_item)
}
binding.spLevel.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
updateFilter(false)
}

override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
}

private fun updateFilter(filter: String, init: Boolean) {
private fun updateFilter(init: Boolean) {

val filter = binding.etFilter.text?.toString() ?: ""
val level = binding.spLevel.selectedItemPosition.takeIf { it > 0 }
?.let { LogAdapter.Item.Level.values()[it - 1] }
val filterIsActive = filter.isNotEmpty() || level != null

if (loading || (init && filter.isEmpty())) {
L.d { "updateFilter: $init | $filter | $level | $filterIsActive" }

if (loading || (init && !filterIsActive)) {
updateInfos()
return
}

filterJob?.cancel()

if (filter.isEmpty()) {
if (!filterIsActive) {
adapter.update(logs, filter)
updateInfos()
return
}

filterJob = lifecycleScope.launch(Dispatchers.IO) {
val filtered = logs.filter { it.text.contains(filter, true) || it.level.name.contains(filter, true) }
val filtered = logs
.filter {
(it.text.contains(filter, true) || it.level.name.contains(filter, true)) &&
(level == null || it.level.level >= level.level)
}
withContext(Dispatchers.Main) {
adapter.update(filtered, filter)
updateInfos()
Expand Down
Loading

0 comments on commit 0f09866

Please sign in to comment.