Skip to content
This repository was archived by the owner on Jun 27, 2020. It is now read-only.

Commit 7974c4f

Browse files
Merge pull request #182 from yevhenii-kanivets/172_redesign_records_list
#172. Redesign records list.
2 parents 43301d7 + 9ae1f75 commit 7974c4f

File tree

17 files changed

+277
-173
lines changed

17 files changed

+277
-173
lines changed

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,5 @@ dependencies {
8888
annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
8989
provided 'org.glassfish:javax.annotation:10.0-b28'
9090
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
91+
implementation 'com.android.support:cardview-v7:27.1.1'
9192
}

app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/edit/fragment/AccountOperationsFragment.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import android.view.View
55
import com.blogspot.e_kanivets.moneytracker.R
66
import com.blogspot.e_kanivets.moneytracker.activity.base.BaseFragment
77
import com.blogspot.e_kanivets.moneytracker.adapter.RecordAdapter
8+
import com.blogspot.e_kanivets.moneytracker.controller.FormatController
89
import com.blogspot.e_kanivets.moneytracker.controller.data.AccountController
910
import com.blogspot.e_kanivets.moneytracker.controller.data.RecordController
1011
import com.blogspot.e_kanivets.moneytracker.controller.data.TransferController
12+
import com.blogspot.e_kanivets.moneytracker.entity.RecordItem
1113
import com.blogspot.e_kanivets.moneytracker.entity.data.Account
1214
import com.blogspot.e_kanivets.moneytracker.entity.data.Category
1315
import com.blogspot.e_kanivets.moneytracker.entity.data.Record
1416
import com.blogspot.e_kanivets.moneytracker.entity.data.Transfer
17+
import com.blogspot.e_kanivets.moneytracker.util.RecordItemsBuilder
1518
import kotlinx.android.synthetic.main.fragment_account_operations.*
1619
import javax.inject.Inject
1720

@@ -23,6 +26,8 @@ class AccountOperationsFragment : BaseFragment() {
2326
internal lateinit var recordController: RecordController
2427
@Inject
2528
internal lateinit var transferController: TransferController
29+
@Inject
30+
internal lateinit var formatController: FormatController
2631

2732
private lateinit var account: Account
2833

@@ -34,17 +39,17 @@ class AccountOperationsFragment : BaseFragment() {
3439
}
3540

3641
override fun initViews(view: View) {
37-
recyclerView.adapter = RecordAdapter(requireContext(), getRecords(), false, null)
42+
recyclerView.adapter = RecordAdapter(requireContext(), getRecordItems(), false, null)
3843
}
3944

40-
private fun getRecords(): List<Record> {
45+
private fun getRecordItems(): List<RecordItem> {
4146
val accountRecords = recordController.getRecordsForAccount(account)
4247
val accountTransfers = transferController.getTransfersForAccount(account)
4348

4449
accountRecords += obtainRecordsFromTransfers(accountTransfers)
4550
accountRecords.sortByDescending { it.time }
4651

47-
return accountRecords
52+
return RecordItemsBuilder().getRecordItems(accountRecords)
4853
}
4954

5055
private fun obtainRecordsFromTransfers(transfers: List<Transfer>): List<Record> {

app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/AddRecordActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ private boolean addRecord() {
366366
}
367367

368368
private void updateDateAndTime() {
369-
tvDate.setText(formatController.formatDate(timestamp));
369+
tvDate.setText(formatController.formatDateToNumber(timestamp));
370370
tvTime.setText(formatController.formatTime(timestamp));
371371
}
372372

app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/MainActivity.kt

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,20 @@ import com.blogspot.e_kanivets.moneytracker.controller.data.AccountController
1515
import com.blogspot.e_kanivets.moneytracker.controller.data.ExchangeRateController
1616
import com.blogspot.e_kanivets.moneytracker.controller.data.RecordController
1717
import com.blogspot.e_kanivets.moneytracker.entity.Period
18+
import com.blogspot.e_kanivets.moneytracker.entity.RecordItem
1819
import com.blogspot.e_kanivets.moneytracker.entity.data.Record
1920
import com.blogspot.e_kanivets.moneytracker.report.ReportMaker
2021
import com.blogspot.e_kanivets.moneytracker.ui.AppRateDialog
2122
import com.blogspot.e_kanivets.moneytracker.util.AnswersProxy
23+
import com.blogspot.e_kanivets.moneytracker.util.RecordItemsBuilder
2224
import kotlinx.android.synthetic.main.activity_main.*
2325
import kotlinx.android.synthetic.main.content_main.*
2426
import javax.inject.Inject
2527

2628
class MainActivity : BaseDrawerActivity() {
2729

2830
private lateinit var recordList: List<Record>
31+
private var recordItems: List<RecordItem> = listOf()
2932
private lateinit var period: Period
3033
private lateinit var recordAdapter: RecordAdapter
3134

@@ -91,8 +94,7 @@ class MainActivity : BaseDrawerActivity() {
9194
private fun editRecord(position: Int) {
9295
AnswersProxy.get().logButton("Edit Record")
9396

94-
// Minus one because of list view's header view
95-
val record = recordList[position - 1]
97+
val record = recordList[position - 1 - getCountHeadersItems(position - 1)]
9698
startAddRecordActivity(record, AddRecordActivity.Mode.MODE_EDIT, record.type)
9799
}
98100

@@ -134,17 +136,28 @@ class MainActivity : BaseDrawerActivity() {
134136
override fun update() {
135137
recordList = recordController.getRecordsForPeriod(period)
136138
recordList = recordList.reversed()
139+
recordItems = RecordItemsBuilder().getRecordItems(recordList)
137140

138141
val currency = currencyController.readDefaultCurrency()
139142

140143
val reportMaker = ReportMaker(rateController)
141144
val report = reportMaker.getRecordReport(currency, period, recordList)
142145

143-
recordAdapter.setRecords(recordList, report, currency, reportMaker.currencyNeeded(currency, recordList))
146+
recordAdapter.setRecords(recordItems, report, currency, reportMaker.currencyNeeded(currency, recordList))
144147

145148
fillDefaultAccount()
146149
}
147150

151+
private fun getCountHeadersItems(position: Int): Int {
152+
var countHeadersItems = 0
153+
for (inOfData in 0 until position) {
154+
if (recordItems[inOfData] is RecordItem.Header) {
155+
countHeadersItems++
156+
}
157+
}
158+
return countHeadersItems
159+
}
160+
148161
private fun showAppRateDialog() {
149162
AnswersProxy.get().logEvent("Show App Rate Dialog")
150163
val dialog = AppRateDialog(this)

app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/RecordAdapter.kt

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import android.widget.TextView
1111
import com.blogspot.e_kanivets.moneytracker.MtApp
1212
import com.blogspot.e_kanivets.moneytracker.R
1313
import com.blogspot.e_kanivets.moneytracker.controller.FormatController
14-
import com.blogspot.e_kanivets.moneytracker.entity.data.Record
14+
import com.blogspot.e_kanivets.moneytracker.entity.RecordItem
1515
import com.blogspot.e_kanivets.moneytracker.report.record.IRecordReport
1616
import com.blogspot.e_kanivets.moneytracker.ui.presenter.ShortSummaryPresenter
17+
import kotlinx.android.synthetic.main.view_header_date.view.*
1718
import kotlinx.android.synthetic.main.view_record.view.*
19+
import kotlinx.android.synthetic.main.view_record.view.container
1820
import kotlinx.android.synthetic.main.view_summary_records.view.*
1921
import javax.inject.Inject
2022

@@ -30,16 +32,16 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
3032
private var red: Int
3133
private var green: Int
3234

33-
private var records: List<Record>
35+
private var items: List<RecordItem>
3436
private var context: Context
3537

3638
private var summaryPresenter: ShortSummaryPresenter
37-
private var isHeaderViewNeeded: Boolean = false
38-
private var headerViewHolder: HeaderViewHolder
39+
private var isSummaryViewNeeded: Boolean = false
40+
private var summaryViewHolder: SummaryViewHolder
3941

40-
constructor(context: Context, records: List<Record>, isHeaderViewNeeded: Boolean, itemClickListener: ((Int) -> Unit)?) {
42+
constructor(context: Context, items: List<RecordItem>, isSummaryViewNeeded: Boolean, itemClickListener: ((Int) -> Unit)?) {
4143
this.context = context
42-
this.records = records
44+
this.items = items
4345

4446
MtApp.get().appComponent.inject(this)
4547

@@ -51,68 +53,71 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
5153
summaryPresenter = ShortSummaryPresenter(context)
5254

5355
this.itemClickListener = itemClickListener
54-
this.isHeaderViewNeeded = isHeaderViewNeeded
56+
this.isSummaryViewNeeded = isSummaryViewNeeded
5557

56-
headerViewHolder = HeaderViewHolder(LayoutInflater.from(context).inflate(R.layout.view_summary_records, null), itemClickListener)
57-
summaryPresenter.create(true, headerViewHolder)
58+
summaryViewHolder = SummaryViewHolder(LayoutInflater.from(context).inflate(R.layout.view_summary_records, null), itemClickListener)
59+
summaryPresenter.create(true, summaryViewHolder)
5860
}
5961

60-
override fun getItemCount() = records.size + if (isHeaderViewNeeded) 1 else 0
62+
override fun getItemCount() = items.size + if (isSummaryViewNeeded) 1 else 0
6163

62-
override fun getItemViewType(position: Int): Int = if (position == 0 && isHeaderViewNeeded) {
64+
override fun getItemViewType(position: Int): Int = if (position == 0 && isSummaryViewNeeded) {
65+
TYPE_SUMMARY
66+
} else if (items[position - if (isSummaryViewNeeded) 1 else 0] is RecordItem.Header) {
6367
TYPE_HEADER
6468
} else {
65-
TYPE_ITEM
69+
TYPE_RECORD
6670
}
6771

6872
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
69-
if (viewType == TYPE_HEADER) {
70-
headerViewHolder
71-
} else {
72-
ViewHolder(LayoutInflater.from(context).inflate(R.layout.view_record, parent, false), itemClickListener)
73+
when (viewType) {
74+
TYPE_RECORD -> RecordViewHolder(LayoutInflater.from(context).inflate(R.layout.view_record, parent, false), itemClickListener)
75+
TYPE_HEADER -> HeaderViewHolder(LayoutInflater.from(context).inflate(R.layout.view_header_date, parent, false))
76+
else -> summaryViewHolder
7377
}
7478

75-
override fun onBindViewHolder(rvViewHolder: RecyclerView.ViewHolder, position: Int) {
76-
if (position == 0 && isHeaderViewNeeded) {
79+
override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
80+
if (position == 0 && isSummaryViewNeeded) {
7781
//adapter already bound to view
7882
return
7983
}
8084

81-
val viewHolder = rvViewHolder as ViewHolder
82-
val record: Record = records[position - if (isHeaderViewNeeded) 1 else 0]
83-
viewHolder.container.setBackgroundColor(if (record.isIncome) whiteGreen else whiteRed)
84-
viewHolder.tvPrice.setTextColor(if (record.isIncome) green else red)
85-
86-
viewHolder.tvDateAndTime.text = formatController.formatDateAndTime(record.time)
87-
val price = (if (record.isIncome) record.fullPrice else getNegative(record.fullPrice))
88-
viewHolder.tvPrice.text = formatController.formatSignedAmount(price)
89-
viewHolder.tvTitle.text = record.title
90-
viewHolder.tvCategory.text = record.category?.name
91-
viewHolder.tvCurrency.text = record.currency
85+
if (viewHolder is RecordViewHolder) {
86+
val record = items[position - if (isSummaryViewNeeded) 1 else 0] as RecordItem.Record
87+
viewHolder.tvPrice.setTextColor(if (record.isIncome) green else red)
88+
89+
val price = (if (record.isIncome) record.fullPrice else getNegative(record.fullPrice))
90+
viewHolder.tvPrice.text = formatController.formatSignedAmount(price)
91+
viewHolder.tvTitle.text = record.title
92+
viewHolder.tvCategory.text = record.categoryName
93+
viewHolder.tvCurrency.text = record.currency
94+
} else {
95+
val headerViewHolder = viewHolder as HeaderViewHolder
96+
val header = items[position - if (isSummaryViewNeeded) 1 else 0] as RecordItem.Header
97+
headerViewHolder.tvDate.text = header.date
98+
}
9299
}
93100

94101
private fun getNegative(number: Double): Double {
95102
return -1 * number
96103
}
97104

98-
fun setRecords(recordsList: List<Record>, report: IRecordReport?, currency: String, ratesNeeded: List<String>) {
99-
records = recordsList
105+
fun setRecords(itemsList: List<RecordItem>, report: IRecordReport?, currency: String, ratesNeeded: List<String>) {
106+
items = itemsList
100107
summaryPresenter.update(report, currency, ratesNeeded)
101108
notifyDataSetChanged()
102109
}
103110

104-
class ViewHolder : RecyclerView.ViewHolder {
111+
class RecordViewHolder : RecyclerView.ViewHolder {
105112

106113
var container: LinearLayout
107-
var tvDateAndTime: TextView
108114
var tvPrice: TextView
109115
var tvTitle: TextView
110116
var tvCategory: TextView
111117
var tvCurrency: TextView
112118

113119
constructor(view: View, itemClickListener: ((Int) -> Unit)?) : super(view) {
114120
container = view.container
115-
tvDateAndTime = view.tvDateAndTime
116121
tvPrice = view.tvPrice
117122
tvTitle = view.tvTitle
118123
tvCategory = view.tvCategory
@@ -124,7 +129,11 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
124129
}
125130
}
126131

127-
class HeaderViewHolder : RecyclerView.ViewHolder, ShortSummaryPresenter.SummaryViewInterface {
132+
class HeaderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
133+
val tvDate: TextView = view.tvDate
134+
}
135+
136+
class SummaryViewHolder : RecyclerView.ViewHolder, ShortSummaryPresenter.SummaryViewInterface {
128137

129138
private var tvPeriod: TextView
130139
private var tvTotalIncome: TextView
@@ -145,15 +154,15 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
145154
tvTotalExpense = view.tvTotalExpense
146155
tvTotal = view.tvTotal
147156

148-
view.setOnClickListener {
157+
view.cvSummary.setOnClickListener {
149158
itemClickListener?.invoke(0)
150159
}
151160
}
152161
}
153162

154163
companion object {
155-
156-
private const val TYPE_HEADER = 0
157-
private const val TYPE_ITEM = 1
164+
private const val TYPE_SUMMARY = 0
165+
private const val TYPE_HEADER = 1
166+
private const val TYPE_RECORD = 2
158167
}
159168
}

app/src/main/java/com/blogspot/e_kanivets/moneytracker/controller/FormatController.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ public class FormatController {
2020
public static final String PRECISION_NONE = "precision_none";
2121

2222
@SuppressLint("SimpleDateFormat")
23-
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
23+
private static final SimpleDateFormat shortDateFormat = new SimpleDateFormat("yyyy-MM-dd");
24+
@SuppressLint("SimpleDateFormat")
25+
private static final SimpleDateFormat fullDateFormat = new SimpleDateFormat("d MMMM yyyy");
2426
@SuppressLint("SimpleDateFormat")
2527
private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
2628
@SuppressLint("SimpleDateFormat")
@@ -72,8 +74,12 @@ public String formatExpense(double amount, String currency) {
7274
return (amount > 0 ? "+ " : "- ") + formatAmount(Math.abs(amount)) + " " + currency;
7375
}
7476

75-
public String formatDate(long timestamp) {
76-
return dateFormat.format(new Date(timestamp));
77+
public String formatDateToNumber(long timestamp) {
78+
return shortDateFormat.format(new Date(timestamp));
79+
}
80+
81+
public String formatDateToString(long timestamp) {
82+
return fullDateFormat.format(new Date(timestamp));
7783
}
7884

7985
public String formatTime(long timestamp) {

app/src/main/java/com/blogspot/e_kanivets/moneytracker/di/AppComponent.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.blogspot.e_kanivets.moneytracker.ui.PeriodSpinner;
2727
import com.blogspot.e_kanivets.moneytracker.ui.presenter.AccountsSummaryPresenter;
2828
import com.blogspot.e_kanivets.moneytracker.ui.presenter.ShortSummaryPresenter;
29+
import com.blogspot.e_kanivets.moneytracker.util.RecordItemsBuilder;
2930

3031
import javax.inject.Singleton;
3132

@@ -87,4 +88,6 @@ public interface AppComponent {
8788
void inject(EditAccountFragment editAccountFragment);
8889

8990
void inject(AccountOperationsFragment accountRecordsFragment);
91+
92+
void inject(RecordItemsBuilder recordItemsBuilder);
9093
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.blogspot.e_kanivets.moneytracker.entity
2+
3+
sealed class RecordItem {
4+
5+
data class Header(val date: String) : RecordItem()
6+
7+
data class Record(val title: String, val categoryName: String, val fullPrice: Double, val currency: String, val isIncome: Boolean) : RecordItem() {
8+
constructor(record: com.blogspot.e_kanivets.moneytracker.entity.data.Record) : this(record.title, record.category?.name?.toString().orEmpty(), record.fullPrice, record.currency, record.isIncome)
9+
}
10+
}

app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/ShortSummaryPresenter.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@ public ShortSummaryPresenter(Context context) {
4646
green = context.getResources().getColor(R.color.green);
4747
}
4848

49-
public View create(boolean shortSummary, RecordAdapter.HeaderViewHolder mainViewHolder) {
49+
public View create(boolean shortSummary, RecordAdapter.SummaryViewHolder mainViewHolder) {
5050
view = layoutInflater.inflate(R.layout.view_summary_records, null);
5151
view.findViewById(R.id.iv_more).setVisibility(shortSummary ? View.VISIBLE : View.INVISIBLE);
52-
52+
view.setEnabled(false);
53+
view.findViewById(R.id.lvSummary).setClickable(false);
54+
view.findViewById(R.id.cvSummary).setClickable(true);
5355
view.setTag(mainViewHolder != null ? mainViewHolder : new ViewHolder(view));
5456

5557
return view;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.blogspot.e_kanivets.moneytracker.util
2+
3+
import com.blogspot.e_kanivets.moneytracker.MtApp
4+
import com.blogspot.e_kanivets.moneytracker.controller.FormatController
5+
import com.blogspot.e_kanivets.moneytracker.entity.RecordItem
6+
import com.blogspot.e_kanivets.moneytracker.entity.data.Record
7+
import javax.inject.Inject
8+
9+
class RecordItemsBuilder {
10+
11+
@Inject
12+
lateinit var formatController: FormatController
13+
14+
constructor() {
15+
MtApp.get().appComponent.inject(this)
16+
}
17+
18+
fun getRecordItems(recordList: List<Record>): List<RecordItem> {
19+
val recordItems: MutableList<RecordItem> = mutableListOf()
20+
21+
var lastDate: String? = null
22+
for (record in recordList) {
23+
if (formatController.formatDateToString(record.time) != lastDate) {
24+
lastDate = formatController.formatDateToString(record.time)
25+
recordItems.add(RecordItem.Header(lastDate))
26+
}
27+
28+
recordItems.add(RecordItem.Record(record))
29+
}
30+
31+
return recordItems
32+
}
33+
34+
}

0 commit comments

Comments
 (0)