diff --git a/app/build.gradle b/app/build.gradle
index b4711913..e265041e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,9 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+ buildFeatures {
+ viewBinding true
+ }
kotlinOptions {
jvmTarget = '1.8'
}
@@ -42,4 +45,5 @@ dependencies {
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
-}
\ No newline at end of file
+ implementation 'com.google.code.gson:gson:2.10'
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index efd1e519..fcf92f2a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,5 @@
-
+
@@ -19,4 +21,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/java/otus/homework/customview/DetailsActivity.kt b/app/src/main/java/otus/homework/customview/DetailsActivity.kt
new file mode 100644
index 00000000..338ce70d
--- /dev/null
+++ b/app/src/main/java/otus/homework/customview/DetailsActivity.kt
@@ -0,0 +1,30 @@
+package otus.homework.customview
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import otus.homework.customview.databinding.ActivityDetailsBinding
+
+class DetailsActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityDetailsBinding
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityDetailsBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ val type = object : TypeToken>() {}.type
+ binding.chartDetails.setup(
+ Gson().fromJson(intent.getStringExtra(KEY_LIST), type)?: listOf()
+ )
+
+ }
+
+
+ companion object {
+ const val KEY_LIST = "KEY_LIST"
+ }
+
+}
diff --git a/app/src/main/java/otus/homework/customview/DetailsChart.kt b/app/src/main/java/otus/homework/customview/DetailsChart.kt
new file mode 100644
index 00000000..eef2a4ff
--- /dev/null
+++ b/app/src/main/java/otus/homework/customview/DetailsChart.kt
@@ -0,0 +1,286 @@
+package otus.homework.customview
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.CornerPathEffect
+import android.graphics.DashPathEffect
+import android.graphics.Paint
+import android.graphics.Paint.Align
+import android.graphics.Path
+import android.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.AttributeSet
+import android.view.View
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import java.lang.Integer.min
+import java.util.Calendar
+import kotlin.math.ceil
+import kotlin.math.max
+
+class DetailsChart @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+): View(context, attrs) {
+
+ private var items: List = listOf()
+
+ private var chartData: List = listOf()
+ private var yStep = 5000
+ private var xStep = 1
+ private var xCount = 10
+
+ private val defaultHeight = 100.dp
+ private val defaultColumnWidth = 32.dp
+ private val defaultColumnHeight = 100.dp
+
+ private val calendar = Calendar.getInstance()
+
+ private val noDataPaint: Paint = Paint().apply {
+ textSize = 72.sp.toFloat()
+ color = Color.BLACK
+ textAlign = Paint.Align.CENTER
+ }
+
+ private val lineStrokePaint = Paint().apply {
+ color = Color.GRAY
+ strokeWidth = 1.dp.toFloat()
+ style = Paint.Style.STROKE
+ pathEffect = DashPathEffect(floatArrayOf(5f, 10f, 5f, 10f), 25f)
+ }
+
+ private val textPaint: Paint = Paint().apply {
+ color = Color.GRAY
+ style = Paint.Style.STROKE
+ textSize = 14.sp.toFloat()
+ }
+
+ private val chartPaint: Paint = Paint().apply {
+ color = Color.RED
+ style = Paint.Style.STROKE
+ strokeWidth = 4.dp.toFloat()
+ pathEffect = CornerPathEffect(2.dp.toFloat())
+ }
+
+ val path = Path()
+
+ init {
+ if (isInEditMode) {
+ setup(listOf(
+ PayItem(350, 1694476800),
+ PayItem(589, 1694476800),
+ PayItem(369, 1694563200),
+ PayItem(1000, 1694736000),
+ PayItem(349, 1694822400),
+ ))
+ }
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val wMode = MeasureSpec.getMode(widthMeasureSpec)
+ val hMode = MeasureSpec.getMode(heightMeasureSpec)
+ val wSize = MeasureSpec.getSize(widthMeasureSpec)
+ val hSize = MeasureSpec.getSize(heightMeasureSpec)
+
+ if (items.isEmpty()) {
+ setMeasuredDimension(wSize, max(defaultHeight, hSize))
+ return
+ }
+
+ val newW: Int = when (wMode) {
+ MeasureSpec.EXACTLY -> {
+ wSize
+ }
+ MeasureSpec.AT_MOST -> {
+ min(defaultColumnWidth * xCount, wSize)
+ }
+ else -> {
+ defaultColumnWidth * xCount
+ }
+ }
+
+ when (hMode) {
+ MeasureSpec.EXACTLY -> {
+ setMeasuredDimension(newW, hSize)
+ }
+ MeasureSpec.AT_MOST -> {
+ setMeasuredDimension(newW, min(defaultColumnHeight * 4, hSize))
+ }
+ else -> {
+ setMeasuredDimension(newW, defaultColumnHeight * 4)
+ }
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+
+ if (chartData.isEmpty()) {
+ val textHeight = noDataPaint.fontMetrics.descent - noDataPaint.fontMetrics.ascent
+ canvas.drawText("No data!", (width / 2).toFloat(), height / 2 + textHeight / 3, noDataPaint)
+ return
+ }
+
+ val x0 = 5f
+ val y0 = 5f
+ val xEnd = width - 10f
+ val yEnd = height - 10f - 14.dp
+
+ val xStepP = (xEnd - x0) / (xCount - 1)
+ val yStepP = (yEnd - x0) / 4
+
+ path.reset()
+ for (i in 0..4) {
+ val y = yStepP * i + y0
+ path.moveTo(x0, y)
+ path.lineTo(xEnd, y)
+ }
+
+ for (i in 0 until xCount) {
+ val x = xStepP * i + x0
+ path.moveTo(x, y0)
+ path.lineTo(x, yEnd)
+ }
+
+ canvas.drawPath(path, lineStrokePaint)
+
+ for (i in 0 until xCount) {
+
+ calendar.timeInMillis = chartData[i * xStep].time * 60 * 60 * 24 * 1000
+ val str = "${calendar.get(Calendar.DAY_OF_MONTH)}"
+ if (i == 0) {
+ textPaint.textAlign = Align.LEFT
+ canvas.drawText(str, x0, height - 5f, textPaint)
+ continue
+ }
+ if (i == xCount - 1) {
+ textPaint.textAlign = Align.RIGHT
+ canvas.drawText(str, xStepP * i + x0, height - 5f, textPaint)
+ continue
+ }
+
+ textPaint.textAlign = Align.CENTER
+ canvas.drawText(str, xStepP * i + x0, height - 5f, textPaint)
+ }
+
+ for (i in 4 downTo 1) {
+ textPaint.textAlign = Align.RIGHT
+ canvas.drawText("${yStep * i} р. ", xEnd, (4 - i) * yStepP + 14.dp, textPaint)
+ }
+
+
+ path.reset()
+ var x1 = x0
+ var y1 = yEnd - (chartData[0].amount.toFloat() / yStep * 4) * yStepP / yStep
+ path.moveTo(x1, y1)
+
+ for (i in chartData.withIndex()) {
+ if (i.index == 0) {
+
+ continue
+ }
+
+ val x2 = xStepP / xStep * i.index
+ val y2 = yEnd - i.value.amount * yStepP / yStep
+ val xMid = (x2 - x1) / 2 + x1
+ path.cubicTo(xMid, y1, xMid, y2, x2, y2)
+ x1 = x2
+ y1 = y2
+ }
+ canvas.drawPath(path, chartPaint)
+
+ }
+
+ override fun onSaveInstanceState(): Parcelable {
+ val bundle = Bundle()
+ bundle.putString(SavedState.keyOneCategory, Gson().toJson(items))
+ val superState = super.onSaveInstanceState()
+ return SavedState(superState, bundle)
+ }
+
+ override fun onRestoreInstanceState(state: Parcelable?) {
+ if (state is SavedState) {
+ super.onRestoreInstanceState(state.superState)
+ val type = object : TypeToken>() {}.type
+ items = Gson().fromJson(state.data, type)
+ setup(items)
+ } else {
+ super.onRestoreInstanceState(state)
+ }
+ }
+
+ fun setup(items: List) {
+ this.items = items
+ val data = items.sortedBy { it.time }
+ .map { it.copy(time = it.time / 60 / 60 / 24) }
+ .groupBy { it.time }
+ .map { (day, amounts) -> PayItem(amounts.sumBy { it.amount }, day) }
+
+ val maxAmount = data.maxOf { it.amount }
+ yStep = ceil(maxAmount / 4 / 100f).toInt() * 100
+
+ val maxDay = data.maxOf { it.time }
+ val minDay = data.minOf { it.time }
+
+ val verticalCount: Int = when (val tmpCount = maxDay - minDay + 1) {
+ in 0..2 -> tmpCount.toInt() + 4
+ in 3..4 -> tmpCount.toInt() + 2
+ in 5..10 -> tmpCount.toInt()
+ else -> ceil(tmpCount / 10f).toInt() * 10
+ }
+
+ if (verticalCount > 10) {
+ xCount = 10
+ xStep = verticalCount / 10
+ } else {
+ xCount = verticalCount
+ xStep = 1
+ }
+
+ val prev = (verticalCount - data.size) / 2
+ val startDateDaysScience1970 = data[0].time - prev
+
+ val list: MutableList = mutableListOf()
+ repeat(verticalCount) {
+ val d = startDateDaysScience1970 + it
+ list.add(data.find { it.time == d } ?: PayItem(0, d))
+ }
+ chartData = list
+ }
+
+ data class PayItem(val amount: Int, val time: Long)
+
+ private class SavedState : BaseSavedState {
+
+ var data: String = ""
+
+ constructor(superState: Parcelable?, bundle: Bundle) : super(superState) {
+ data = bundle.getString(keyOneCategory, "")
+ }
+
+ constructor(parcel: Parcel) : super(parcel) {
+ data = parcel.readString() ?: ""
+ }
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ super.writeToParcel(parcel, flags)
+ parcel.writeString(data)
+ }
+
+ companion object CREATOR : Parcelable.Creator {
+
+ const val keyOneCategory = "keyOneCategory"
+
+ override fun createFromParcel(parcel: Parcel): SavedState {
+ return SavedState(parcel)
+ }
+
+ override fun newArray(size: Int): Array {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/java/otus/homework/customview/Ectensions.kt b/app/src/main/java/otus/homework/customview/Ectensions.kt
new file mode 100644
index 00000000..d13ea254
--- /dev/null
+++ b/app/src/main/java/otus/homework/customview/Ectensions.kt
@@ -0,0 +1,7 @@
+package otus.homework.customview
+
+import android.content.res.Resources.getSystem
+
+
+val Int.dp: Int get() = (this * getSystem().displayMetrics.density).toInt()
+val Int.sp: Int get() = (this * getSystem().displayMetrics.scaledDensity).toInt()
diff --git a/app/src/main/java/otus/homework/customview/MainActivity.kt b/app/src/main/java/otus/homework/customview/MainActivity.kt
index 78cb9448..a06b768a 100644
--- a/app/src/main/java/otus/homework/customview/MainActivity.kt
+++ b/app/src/main/java/otus/homework/customview/MainActivity.kt
@@ -1,11 +1,71 @@
package otus.homework.customview
-import androidx.appcompat.app.AppCompatActivity
+import android.content.Intent
import android.os.Bundle
+import android.widget.Toast
+import androidx.appcompat.app.AppCompatActivity
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import otus.homework.customview.DetailsActivity.Companion.KEY_LIST
+import otus.homework.customview.databinding.ActivityMainBinding
+import java.io.BufferedReader
+import java.io.InputStreamReader
class MainActivity : AppCompatActivity() {
+
+ private lateinit var binding: ActivityMainBinding
+
+ private lateinit var data: List
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ if (savedInstanceState == null) {
+ val inputStream = resources.openRawResource(R.raw.payload)
+ val reader = BufferedReader(InputStreamReader(inputStream))
+ val json = StringBuilder()
+ var line: String?
+ while (reader.readLine().also { line = it } != null) {
+ json.append(line)
+ }
+ reader.close()
+
+ val gson = Gson()
+ val type = object : TypeToken>() {}.type
+ data = gson.fromJson(json.toString(), type)
+
+ binding.chart.setup(
+ data
+ .groupBy { it.category }
+ .map { (cat, amounts) ->
+ PieChart.Category.OneCategory(cat, amounts.sumBy { it.amount }) })
+ }
+
+ binding.chart.onCategoryClickListener = object : PieChart.OnCategoryClickListener {
+ override fun onClick(category: PieChart.Category) {
+ val text = when (category) {
+ is PieChart.Category.MultipleCategories -> "${category.names} -> ${category.value}"
+ is PieChart.Category.OneCategory -> "${category.name} -> ${category.value}"
+ }
+ Toast.makeText(this@MainActivity, text, Toast.LENGTH_SHORT).show()
+
+ val list = data.filter {
+ when (category) {
+ is PieChart.Category.MultipleCategories -> it.category in category.names
+ is PieChart.Category.OneCategory -> it.category == category.name
+ }
+ }.map { DetailsChart.PayItem(it.amount, it.time) }
+
+
+
+ val intent = Intent(this@MainActivity, DetailsActivity::class.java)
+ intent.putExtra(KEY_LIST, Gson().toJson(list))
+ startActivity(intent)
+ }
+ }
+
+
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/otus/homework/customview/PayloadItem.kt b/app/src/main/java/otus/homework/customview/PayloadItem.kt
new file mode 100644
index 00000000..cfcd25ca
--- /dev/null
+++ b/app/src/main/java/otus/homework/customview/PayloadItem.kt
@@ -0,0 +1,9 @@
+package otus.homework.customview
+
+data class PayloadItem(
+ val id: Int,
+ val name: String,
+ val amount: Int,
+ val category: String,
+ val time: Long
+)
diff --git a/app/src/main/java/otus/homework/customview/PieChart.kt b/app/src/main/java/otus/homework/customview/PieChart.kt
new file mode 100644
index 00000000..bd5a5830
--- /dev/null
+++ b/app/src/main/java/otus/homework/customview/PieChart.kt
@@ -0,0 +1,296 @@
+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.os.Bundle
+import android.os.Parcel
+import android.os.Parcelable
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import com.google.gson.Gson
+import com.google.gson.reflect.TypeToken
+import java.lang.Integer.min
+import kotlin.math.atan2
+import kotlin.math.max
+
+class PieChart @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0
+): View(context, attrs) {
+
+ var onCategoryClickListener: OnCategoryClickListener? = null
+
+ private val colors = arrayListOf(
+ Color.RED,
+ Color.GREEN,
+ Color.GRAY,
+ Color.CYAN,
+ Color.MAGENTA,
+ Color.YELLOW,
+ Color.BLUE,
+ Color.DKGRAY,
+ Color.BLACK,
+ Color.LTGRAY,
+ Color.BLUE
+ )
+
+ private val defaultRadius = 50.dp
+ private var radius = defaultRadius
+ private val strokeWidth = 50.dp.toFloat()
+ private val maxCategories = 10 // Сколько категорий отображать. Остальные сгруппируются
+
+ private var data: List = listOf()
+ private var chartData: List = listOf()
+ private var allSum = 0
+
+ private var circleX = 0
+ private var circleY = 0
+
+ private val noDataPaint: Paint = Paint().apply {
+ textSize = 72.sp.toFloat()
+ color = Color.BLACK
+ textAlign = Paint.Align.CENTER
+ }
+ private val defaultHeight = 100.dp
+
+ private val categoryPaint: Paint = Paint().apply {
+ style = Paint.Style.STROKE
+ strokeWidth = this@PieChart.strokeWidth
+ }
+
+ private val chartRect = RectF()
+
+ init {
+
+ if (isInEditMode) {
+ setup(listOf(
+ Category.OneCategory("Продукты", 3500),
+ Category.OneCategory("Транспорт", 1000),
+ Category.OneCategory("Спорт", 1648),
+ Category.OneCategory("Кафе и рестораны", 800),
+ Category.OneCategory("Доставка еды", 364),
+ Category.OneCategory("Здоровье", 981),
+ Category.OneCategory("Образование", 2500),
+ Category.OneCategory("Развлечения", 884),
+ Category.OneCategory("Благотворительность", 1200),
+ Category.OneCategory("Разное", 3000)
+ ))
+ }
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ val wMode = MeasureSpec.getMode(widthMeasureSpec)
+ val hMode = MeasureSpec.getMode(heightMeasureSpec)
+ val wSize = MeasureSpec.getSize(widthMeasureSpec)
+ val hSize = MeasureSpec.getSize(heightMeasureSpec)
+
+ if (chartData.isEmpty()) {
+ setMeasuredDimension(wSize, max(defaultHeight, hSize))
+ return
+ }
+
+ val newW: Int = when (wMode) {
+ MeasureSpec.EXACTLY -> {
+ wSize
+ }
+ MeasureSpec.AT_MOST -> {
+ min(hSize, wSize)
+ }
+ else -> {
+ if (hMode == MeasureSpec.UNSPECIFIED)
+ (defaultRadius + strokeWidth * 2).toInt()
+ else
+ hSize
+ }
+ }
+
+ when (hMode) {
+ MeasureSpec.EXACTLY -> {
+ setMeasuredDimension(newW, hSize)
+ }
+ MeasureSpec.AT_MOST -> {
+ if (newW < hSize) {
+ setMeasuredDimension(newW, newW)
+ } else {
+ setMeasuredDimension(newW, hSize)
+ }
+ }
+ else -> {
+ setMeasuredDimension(newW, newW)
+ }
+ }
+ }
+
+ override fun onDraw(canvas: Canvas) {
+ if (chartData.isEmpty()) {
+ val textHeight = noDataPaint.fontMetrics.descent - noDataPaint.fontMetrics.ascent
+ canvas.drawText("No data!", (width / 2).toFloat(), height / 2 + textHeight / 3, noDataPaint)
+ return
+ }
+
+ radius = max(min(width, height) - strokeWidth.toInt() * 2, defaultRadius) / 2
+
+ circleX = width / 2
+ circleY = height / 2
+
+ chartRect.left = circleX - strokeWidth / 2 - radius
+ chartRect.top = circleY - strokeWidth / 2 - radius
+ chartRect.right = circleX + strokeWidth / 2 + radius
+ chartRect.bottom = circleY + strokeWidth / 2 + radius
+
+ var startAngle = 0f
+ var endAngle: Float
+
+ chartData.forEachIndexed { i, it ->
+ endAngle = if (i == chartData.size) {
+ 360f
+ } else {
+ startAngle + (it.value / allSum.toFloat() * 360)
+ }
+ drawChartPart(canvas, startAngle, endAngle, colors[i])
+ startAngle = endAngle
+ }
+
+ }
+
+ private fun drawChartPart(canvas: Canvas, startAngle: Float, endAngle: Float, color: Int) {
+ categoryPaint.color = color
+
+ canvas.drawArc(chartRect, startAngle - 90, endAngle - startAngle, false, categoryPaint)
+ }
+
+ override fun onTouchEvent(event: MotionEvent): Boolean {
+ if (event.action == MotionEvent.ACTION_DOWN) {
+ val tX = event.x.toDouble()
+ val tY = event.y.toDouble()
+
+ val r1 = radius
+ val r2 = radius + strokeWidth
+
+ val l = (tX - circleX) * (tX - circleX) + (tY - circleY) * (tY - circleY)
+
+ if (l >= r1 * r1 && l <= r2 * r2) {
+ var angle = Math.toDegrees(atan2(tY - circleY, tX - circleX)) + 90
+ if (angle < 0)
+ angle += 360
+
+ var startAngle = 0.0
+
+ chartData.forEachIndexed { i, it ->
+ val endAngle: Double = if (i == chartData.size) {
+ 360.0
+ } else {
+ startAngle + (it.value / allSum.toFloat() * 360)
+ }
+
+ if (angle > startAngle && angle < endAngle) {
+ onCategoryClickListener?.onClick(it)
+ return true
+ }
+
+ startAngle = endAngle
+ }
+ }
+ }
+
+ return false
+ }
+
+ override fun onSaveInstanceState(): Parcelable {
+ val bundle = Bundle()
+ bundle.putString(SavedState.keyOneCategory, Gson().toJson(data))
+ val superState = super.onSaveInstanceState()
+ return SavedState(superState, bundle)
+ }
+
+ override fun onRestoreInstanceState(state: Parcelable?) {
+ if (state is SavedState) {
+ super.onRestoreInstanceState(state.superState)
+ val type = object : TypeToken>() {}.type
+ data = Gson().fromJson(state.oneCategoryList, type)
+ setup(data)
+ } else {
+ super.onRestoreInstanceState(state)
+ }
+ }
+
+ fun setup(categories: List) {
+ data = categories
+
+ // Сортируем по убыванию
+ val sorted = categories
+ .sortedBy { it.value}
+ .reversed()
+
+ allSum = 0
+ val list = mutableListOf()
+ val otherCategory = Category.MultipleCategories(arrayListOf(), 0)
+
+ sorted.forEachIndexed { i, cat ->
+ if (i < maxCategories) {
+ list.add(cat)
+ } else {
+ otherCategory.names.add(cat.name)
+ otherCategory.value += cat.value
+ }
+ allSum += cat.value
+ }
+
+ if (otherCategory.value > 0) {
+ list.add(otherCategory)
+ }
+
+ chartData = list
+ }
+
+ sealed class Category {
+
+ abstract val value: Int
+
+ data class OneCategory(val name: String, override val value: Int): Category()
+
+ data class MultipleCategories(val names: MutableList, override var value: Int): Category()
+
+ }
+
+ interface OnCategoryClickListener {
+ fun onClick(category: Category)
+ }
+
+ private class SavedState : BaseSavedState {
+
+ var oneCategoryList: String = ""
+
+ constructor(superState: Parcelable?, bundle: Bundle) : super(superState) {
+ oneCategoryList = bundle.getString(keyOneCategory, "")
+ }
+
+ constructor(parcel: Parcel) : super(parcel) {
+ oneCategoryList = parcel.readString() ?: ""
+ }
+
+ override fun writeToParcel(parcel: Parcel, flags: Int) {
+ super.writeToParcel(parcel, flags)
+ parcel.writeString(oneCategoryList)
+ }
+
+ companion object CREATOR : Parcelable.Creator {
+
+ const val keyOneCategory = "keyOneCategory"
+
+ override fun createFromParcel(parcel: Parcel): SavedState {
+ return SavedState(parcel)
+ }
+
+ override fun newArray(size: Int): Array {
+ return arrayOfNulls(size)
+ }
+ }
+ }
+
+}
diff --git a/app/src/main/res/layout/activity_details.xml b/app/src/main/res/layout/activity_details.xml
new file mode 100644
index 00000000..c49492d0
--- /dev/null
+++ b/app/src/main/res/layout/activity_details.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 79ae6993..6b57c432 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -7,13 +7,14 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
-
-
\ No newline at end of file
+