Skip to content

Commit

Permalink
[MERGE] #9 -> develop
Browse files Browse the repository at this point in the history
[UI/#9] 기록뷰 / UI 구현 및 MpChart 활용한 그래프 구현
  • Loading branch information
Marchbreeze authored Jul 25, 2024
2 parents 4afac5e + 4c70590 commit 2170d48
Show file tree
Hide file tree
Showing 12 changed files with 469 additions and 13 deletions.
34 changes: 24 additions & 10 deletions buildSrc/src/main/kotlin/Dependencies.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
object KotlinDependencies {
const val kotlin = "org.jetbrains.kotlin:kotlin-stdlib:${Versions.kotlinVersion}"
const val coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesAndroidVersion}"
const val jsonSerialization = "org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.kotlinSerializationJsonVersion}"
const val coroutines =
"org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutinesAndroidVersion}"
const val jsonSerialization =
"org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.kotlinSerializationJsonVersion}"
const val dateTime = "org.jetbrains.kotlinx:kotlinx-datetime:${Versions.kotlinDateTimeVersion}"
}

Expand All @@ -10,22 +12,26 @@ object AndroidXDependencies {
const val splashScreen = "androidx.core:core-splashscreen:${Versions.splashVersion}"

const val appCompat = "androidx.appcompat:appcompat:${Versions.appCompatVersion}"
const val constraintLayout = "androidx.constraintlayout:constraintlayout:${Versions.constraintLayoutVersion}"
const val constraintLayout =
"androidx.constraintlayout:constraintlayout:${Versions.constraintLayoutVersion}"
const val startup = "androidx.startup:startup-runtime:${Versions.appStartUpVersion}"
const val fragment = "androidx.fragment:fragment-ktx:${Versions.fragmentKtxVersion}"
const val legacy = "androidx.legacy:legacy-support-v4:${Versions.legacySupportVersion}"
const val security = "androidx.security:security-crypto:${Versions.securityVersion}"

const val navigationFragment = "androidx.navigation:navigation-fragment-ktx:${Versions.navigationVersion}"
const val navigationFragment =
"androidx.navigation:navigation-fragment-ktx:${Versions.navigationVersion}"
const val navigationUi = "androidx.navigation:navigation-ui-ktx:${Versions.navigationVersion}"

const val lifeCycleKtx = "androidx.lifecycle:lifecycle-runtime-ktx:${Versions.lifecycleVersion}"
const val lifecycleJava8 = "androidx.lifecycle:lifecycle-common-java8:${Versions.lifecycleVersion}"
const val lifecycleJava8 =
"androidx.lifecycle:lifecycle-common-java8:${Versions.lifecycleVersion}"
const val workManager = "androidx.work:work-runtime-ktx:${Versions.workManagerVersion}"

const val hiltWorkManager = "androidx.hilt:hilt-work:1.0.0"
const val hilt = "com.google.dagger:hilt-android:${Versions.hiltVersion}"
const val ossLicense = "com.google.android.gms:play-services-oss-licenses:${Versions.ossVersion}"
const val ossLicense =
"com.google.android.gms:play-services-oss-licenses:${Versions.ossVersion}"
}

object TestDependencies {
Expand All @@ -35,7 +41,8 @@ object TestDependencies {
}

object MaterialDesignDependencies {
const val materialDesign = "com.google.android.material:material:${Versions.materialDesignVersion}"
const val materialDesign =
"com.google.android.material:material:${Versions.materialDesignVersion}"
}

object KaptDependencies {
Expand All @@ -48,23 +55,30 @@ object ThirdPartyDependencies {
const val coil = "io.coil-kt:coil:${Versions.coilVersion}"

const val retrofit = "com.squareup.retrofit2:retrofit:${Versions.retrofitVersion}"
const val retrofitJsonConverter = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:${Versions.kotlinSerializationConverterVersion}"
const val retrofitJsonConverter =
"com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:${Versions.kotlinSerializationConverterVersion}"
const val okHttpBom = "com.squareup.okhttp3:okhttp-bom:${Versions.okHttpVersion}"
const val okHttp = "com.squareup.okhttp3:okhttp"
const val okHttpLoggingInterceptor = "com.squareup.okhttp3:logging-interceptor"

const val timber = "com.jakewharton.timber:timber:${Versions.timberVersion}"

const val ossLicense = "com.google.android.gms:play-services-oss-licenses:${Versions.ossVersion}"
const val ossLicense =
"com.google.android.gms:play-services-oss-licenses:${Versions.ossVersion}"

const val progressView = "com.github.skydoves:progressview:${Versions.progressViewVersion}"
const val balloon = "com.github.skydoves:balloon:${Versions.balloonVersion}"
const val lottie = "com.airbnb.android:lottie:${Versions.lottieVersion}"
const val circularProgressBar = "com.mikhaellopez:circularprogressbar:${Versions.circularProgressBar}"
const val circularProgressBar =
"com.mikhaellopez:circularprogressbar:${Versions.circularProgressBar}"
const val circleIndicator = "me.relex:circleindicator:${Versions.circleIndicatorVersion}"
const val shimmer = "com.facebook.shimmer:shimmer:${Versions.shimmerVersion}"
}

object JitPackDependencies {
const val mpChart = "com.github.PhilJay:MPAndroidChart:${Versions.mpChartVersion}"
}

object ClassPathPlugins {
const val gradle = "com.android.tools.build:gradle:${Versions.gradleVersion}"
const val kotlinGradle = "org.jetbrains.kotlin:kotlin-gradle-plugin:${Versions.kotlinVersion}"
Expand Down
2 changes: 2 additions & 0 deletions buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ object Versions {
const val circleIndicatorVersion = "2.1.6"
const val shimmerVersion = "0.5.0"

const val mpChartVersion = "v3.1.0"

const val junitVersion = "4.13.2"
const val espressoVersion = "3.5.1"
const val androidTestVersion = "1.1.2"
Expand Down
4 changes: 4 additions & 0 deletions presentation/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,8 @@ dependencies {
implementation(circularProgressBar)
implementation(circleIndicator)
}

JitPackDependencies.run {
implementation(mpChart)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,140 @@ package com.kkkk.presentation.main.report

import android.os.Bundle
import android.view.View
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.formatter.ValueFormatter
import com.kkkk.core.base.BaseFragment
import com.kkkk.core.extension.colorOf
import com.kkkk.core.extension.stringOf
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kr.genti.presentation.R
import kr.genti.presentation.databinding.FragmentReportBinding
import java.text.SimpleDateFormat
import java.util.Locale

@AndroidEntryPoint
class ReportFragment : BaseFragment<FragmentReportBinding>(R.layout.fragment_report) {

private val viewModel by activityViewModels<ReportViewModel>()

override fun onViewCreated(
view: View,
savedInstanceState: Bundle?,
) {
super.onViewCreated(view, savedInstanceState)

binding.vm = viewModel
observeReportMonth()
observeChartEntry()
}

private fun observeReportMonth() {
viewModel.reportMonth.observe(viewLifecycleOwner) { month ->
binding.tvReportMonth.text = when (month) {
1 -> stringOf(R.string.report_tv_month_1)
3 -> stringOf(R.string.report_tv_month_3)
6 -> stringOf(R.string.report_tv_month_6)
else -> return@observe
}
viewModel.setGraphValue()
}
}

private fun observeChartEntry() {
viewModel.chartEntry.flowWithLifecycle(lifecycle).distinctUntilChanged().onEach {
if (it.isNotEmpty()) {
binding.chartReport.apply {
data = LineData(
LineDataSet(
viewModel.chartEntry.value,
CHART_REPORT
).setDataSettings()
)
invalidate()
}
setGraphSettings()
}
}.launchIn(lifecycleScope)
}

private fun LineDataSet.setDataSettings(): LineDataSet {
this.apply {
color = colorOf(R.color.purple_50)
circleRadius = 8f
setCircleColor(colorOf(R.color.purple_50))
setDrawFilled(true)
setDrawValues(false)
lineWidth = 4F
setDrawCircleHole(false)
fillColor = colorOf(R.color.purple_10)
fillAlpha = 255
isHighlightEnabled = false
mode = LineDataSet.Mode.LINEAR
}
return this
}

private fun setGraphSettings() {
binding.chartReport.apply {
setXAxisSettings(this)
setYAxisSettings(this)
setCommonSettings(this)
}
}

private fun setXAxisSettings(chart: LineChart) {
chart.xAxis.apply {
valueFormatter = object : ValueFormatter() {
override fun getFormattedValue(value: Float): String? {
return if (value.toInt() in viewModel.nowList.indices) {
DATE_FORMAT.parse(viewModel.nowList[value.toInt()].second)
?.let { DISPLAY_DATE_FORMAT.format(it) }
} else {
""
}
}
}
position = XAxis.XAxisPosition.BOTTOM
granularity = 1f
axisMinimum = 0.7f
axisMaximum = viewModel.chartEntry.value.size - 0.8f
setDrawGridLines(false)
setDrawAxisLine(false)
textSize = 15f
textColor = colorOf(R.color.gray_600)
}
}

private fun setYAxisSettings(chart: LineChart) {
chart.axisLeft.apply {
isEnabled = false
axisMaximum = 100f
}
chart.axisRight.isEnabled = false
}

private fun setCommonSettings(chart: LineChart) {
chart.apply {
legend.isEnabled = false
description.isEnabled = false
setScaleEnabled(false)
setDragEnabled(false)
setExtraOffsets(0f, 0f, 0f, 20f)
}
}

companion object {
private const val CHART_REPORT = "CHART_REPORT"
val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
val DISPLAY_DATE_FORMAT = SimpleDateFormat("MM/dd", Locale.getDefault())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.kkkk.presentation.main.report

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.github.mikephil.charting.data.Entry
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject

@HiltViewModel
class ReportViewModel
@Inject
constructor(
// private val authRepository: AuthRepository,
) : ViewModel() {

val isChangingMonth = MutableLiveData<Boolean>(false)
val reportMonth = MutableLiveData<Int>(3)

val mockList = listOf(
Pair(10f, "2024-02-28"),
Pair(20f, "2024-03-28"),
Pair(20f, "2024-04-02"),
Pair(30f, "2024-04-29"),
Pair(10f, "2024-05-08"),
Pair(20f, "2024-05-18"),
Pair(20f, "2024-05-22"),
Pair(30f, "2024-06-09"),
Pair(100f, "2024-06-13"),
Pair(90f, "2024-06-23")
)
var nowList = listOf<Pair<Float, String>>()

private val _chartEntry = MutableStateFlow<MutableList<Entry>>(mutableListOf())
val chartEntry: StateFlow<MutableList<Entry>> = _chartEntry

init {
setGraphValue()
}

fun setIsChangingMonth() {
isChangingMonth.value = isChangingMonth.value?.not() ?: false
}

fun setReportMonth(month: Int) {
reportMonth.value = month
isChangingMonth.value = false
}

fun setGraphValue() {
// TODO 서버 붙이고 수정
nowList = when (reportMonth.value) {
1 -> mockList.subList(5, 10)
3 -> mockList.subList(2, 10)
6 -> mockList.subList(0, 10)
else -> return
}
val tempList = arrayListOf<Entry>()
nowList.forEachIndexed { index, (value, _) ->
tempList.add(Entry(index.toFloat(), value))
}
_chartEntry.value = tempList
}
}
16 changes: 16 additions & 0 deletions presentation/src/main/res/drawable/ic_drop_down.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="44dp"
android:height="44dp"
android:viewportWidth="44"
android:viewportHeight="44">
<path
android:pathData="M22,22m-13,0a13,13 0,1 1,26 0a13,13 0,1 1,-26 0"
android:fillColor="#784DF0"/>
<path
android:pathData="M17,20L22,25L27,20"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#FDFDFD"
android:strokeLineCap="round"/>
</vector>
16 changes: 16 additions & 0 deletions presentation/src/main/res/drawable/ic_drop_up.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="44dp"
android:height="44dp"
android:viewportWidth="44"
android:viewportHeight="44">
<path
android:pathData="M22,22m-13,0a13,13 0,1 1,26 0a13,13 0,1 1,-26 0"
android:fillColor="#784DF0"/>
<path
android:pathData="M27,24L22,19L17,24"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:strokeColor="#FDFDFD"
android:strokeLineCap="round"/>
</vector>
13 changes: 13 additions & 0 deletions presentation/src/main/res/drawable/ic_next_purple.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="10dp"
android:height="16dp"
android:viewportWidth="10"
android:viewportHeight="16">
<path
android:pathData="M3,13L8,8L3,3"
android:strokeLineJoin="round"
android:strokeWidth="1.5"
android:fillColor="#00000000"
android:strokeColor="#784DF0"
android:strokeLineCap="round"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/gray_100" />
<corners
android:radius="8dp" />
</shape>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="line">
<stroke
android:width="1dp"
android:color="@color/gray_300"
android:dashWidth="6dp"
android:dashGap="6dp"/>
</shape>
Loading

0 comments on commit 2170d48

Please sign in to comment.