Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR #59

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

PR #59

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ plugins {
}

android {
compileSdkVersion 30
compileSdkVersion 33
buildToolsVersion "30.0.3"

defaultConfig {
applicationId "otus.homework.customview"
minSdkVersion 23
targetSdkVersion 30
targetSdkVersion 33
versionCode 1
versionName "1.0"

Expand Down Expand Up @@ -42,4 +42,5 @@ dependencies {
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.code.gson:gson:2.8.9'
}
3 changes: 2 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.CustomView">
<activity android:name=".MainActivity">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
114 changes: 114 additions & 0 deletions app/src/main/assets/payload.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
[
{
"id": 1,
"name": "Азбука Вкуса",
"amount": 1580,
"category": "Продукты",
"time": 1623318531
},
{
"id": 2,
"name": "Ригла",
"amount": 4990,
"category": "Здоровье",
"time": 1623322251
},
{
"id": 3,
"name": "Пятерочка",
"amount": 129,
"category": "Продукты",
"time": 1623322371
},
{
"id": 4,
"name": "Truffo",
"amount": 4541,
"category": "Кафе и рестораны",
"time": 1623326031
},
{
"id": 5,
"name": "Simple Wine",
"amount": 1600,
"category": "Алкоголь",
"time": 1623329631
},
{
"id": 6,
"name": "Азбука Вкуса Экспресс",
"amount": 1841,
"category": "Доставка еды",
"time": 1623322371
},
{
"id": 7,
"name": "Uber",
"amount": 369,
"category": "Транспорт",
"time": 1623416031
},
{
"id": 8,
"name": "Метро",
"amount": 100,
"category": "Транспорт",
"time": 1623416211
},
{
"id": 9,
"name": "Стоматология",
"amount": 8000,
"category": "Здоровье",
"time": 1623419811
},
{
"id": 10,
"name": "Пятерочка",
"amount": 809,
"category": "Продукты",
"time": 1623419934
},
{
"id": 11,
"name": "Бассейн",
"amount": 1000,
"category": "Спорт",
"time": 1623419934
},
{
"id": 12,
"name": "Uber",
"amount": 389,
"category": "Транспорт",
"time": 1623419934
},
{
"id": 13,
"name": "Стоматология",
"amount": 3000,
"category": "Здоровье",
"time": 1623419811
},
{
"id": 14,
"name": "Стоматология",
"amount": 1250,
"category": "Здоровье",
"time": 1623419811
},
{
"id": 15,
"name": "Стоматология",
"amount": 1500,
"category": "Здоровье",
"time": 1623419811
},
{
"id": 15,
"name": "Стоматология",
"amount": 1500,
"category": "Здоровье",
"time": 1623419811
}
]
126 changes: 126 additions & 0 deletions app/src/main/java/otus/homework/customview/BarChartView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package otus.homework.customview

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import kotlin.math.min

class BarChartView @JvmOverloads constructor (
context: Context,
attrs: AttributeSet? = null,
) : View(context, attrs) {

private val list = ArrayList<PayLoadModel>()
private var maxValue = 0
private var barWidth = context.dpToPixels(50)
private var paintBaseFill : Paint = Paint()
private var paintText : Paint = Paint()
private var threshold: Int = Int.MAX_VALUE
private var paintStroke : Paint = Paint()
private val rect = RectF()
private val textAmountSize: Float = context.spToPixels(12)
private var wSize: Int = 0

companion object {
private const val DEFAULT_MARGIN_BAR_X = 30
private const val DEFAULT_MARGIN_TEXT_BOTTOM_Y = 30
private const val DEFAULT_MARGIN_TEXT_TOP_Y = 60
}

init {
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.BarChartView)
val baseColor: Int =
typedArray.getColor(
R.styleable.BarChartView_baseColor, Color.parseColor("#1A237E"))
val threshold = typedArray.getInt(R.styleable.BarChartView_threshold, Int.MAX_VALUE)
val barWidth =
typedArray.getDimension(
R.styleable.BarChartView_barWidth, barWidth)
typedArray.recycle()
setup(baseColor, threshold, barWidth)
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val wMode = MeasureSpec.getMode(widthMeasureSpec)
wSize = MeasureSpec.getSize(widthMeasureSpec)
val hSize = MeasureSpec.getSize(heightMeasureSpec)

when (wMode) {
MeasureSpec.EXACTLY -> setMeasuredDimension(wSize, hSize)
MeasureSpec.AT_MOST -> {
val newW = Integer.min((list.size * barWidth).toInt(), wSize)
setMeasuredDimension(newW, hSize)
}
MeasureSpec.UNSPECIFIED -> setMeasuredDimension((list.size * barWidth).toInt(), hSize)
}
}

override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)

if (list.size == 0) return

val widthPerView = width.toFloat() / list.size
var currentX = 0f
val heightWithMargin = (height - 200)
val heightPerValue = heightWithMargin.toFloat() / maxValue

for (item in list) {
val barX = currentX + DEFAULT_MARGIN_BAR_X
val barY =
min((heightWithMargin - heightPerValue * item.amount) + DEFAULT_MARGIN_TEXT_TOP_Y,
heightWithMargin.toFloat())
rect.set(
barX,
barY,
(currentX + widthPerView),
heightWithMargin.toFloat(),
)
canvas.drawRect(rect, paintBaseFill)
canvas.drawRect(rect, paintStroke)
canvas.drawText(item.amount.toString(), barX, barY - DEFAULT_MARGIN_TEXT_BOTTOM_Y, paintText)
currentX += widthPerView
}

canvas.drawLine(
DEFAULT_MARGIN_BAR_X.toFloat(),
heightWithMargin.toFloat(),
width.toFloat() + 100,
heightWithMargin.toFloat() , paintStroke)
}

fun setValues(values : List<PayLoadModel>) {
list.clear()
list.addAll(values)
maxValue = list.maxOf { it.amount }

requestLayout()
invalidate()
}

private fun setup(baseColor: Int, threshold : Int, barWidth : Float) {

paintBaseFill = Paint().apply {
color = baseColor
style = Paint.Style.FILL
}

paintText = Paint().apply {
color = baseColor
style = Paint.Style.FILL
textSize = textAmountSize
}

paintStroke = Paint().apply {
color = Color.BLACK
style = Paint.Style.STROKE
strokeWidth = 2.0f
}
this.threshold = threshold
this.barWidth = barWidth
}
}
8 changes: 8 additions & 0 deletions app/src/main/java/otus/homework/customview/BaseChartState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package otus.homework.customview

import android.os.Parcelable
import android.view.View

class BaseChartState(
private val superSavedState: Parcelable?,
val dataList: List<PayLoadModel>): View.BaseSavedState(superSavedState), Parcelable
3 changes: 3 additions & 0 deletions app/src/main/java/otus/homework/customview/BaseValueModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package otus.homework.customview

abstract class BaseValueModel
20 changes: 20 additions & 0 deletions app/src/main/java/otus/homework/customview/Extensions.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package otus.homework.customview

import android.content.Context
import android.graphics.Canvas
import android.text.StaticLayout
import android.util.TypedValue
import androidx.core.graphics.withTranslation


fun Context.dpToPixels(dp: Int) = dp * this.resources.displayMetrics.density

fun Context.spToPixels(sp: Int) =
TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, sp.toFloat(), this.resources.displayMetrics)

fun StaticLayout.draw(canvas: Canvas, x: Float, y: Float) {
canvas.withTranslation(x, y) {
draw(this)
}
}
24 changes: 24 additions & 0 deletions app/src/main/java/otus/homework/customview/FileUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package otus.homework.customview

import android.content.Context
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

class FileUtils {

object AssetsLoader {

fun loadTextFromAsset(context: Context, file: String): String {
return context.assets.open(file).bufferedReader().use { reader ->
reader.readText()
}
}

fun getDataFromText(text: String): List<PayLoadModel> {
val listPayLoadModelType = object : TypeToken<List<PayLoadModel>>() {}.type
val payloads: List<PayLoadModel> = Gson().fromJson(text, listPayLoadModelType)
return payloads
}

}
}
Loading