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

Commit 2f46e3f

Browse files
#172. Redesign records list.
1 parent 43301d7 commit 2f46e3f

File tree

18 files changed

+270
-167
lines changed

18 files changed

+270
-167
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: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ 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.HeaderItem
13+
import com.blogspot.e_kanivets.moneytracker.entity.RecordAdapterData
14+
import com.blogspot.e_kanivets.moneytracker.entity.RecordItem
1115
import com.blogspot.e_kanivets.moneytracker.entity.data.Account
1216
import com.blogspot.e_kanivets.moneytracker.entity.data.Category
1317
import com.blogspot.e_kanivets.moneytracker.entity.data.Record
@@ -23,6 +27,8 @@ class AccountOperationsFragment : BaseFragment() {
2327
internal lateinit var recordController: RecordController
2428
@Inject
2529
internal lateinit var transferController: TransferController
30+
@Inject
31+
internal lateinit var formatController: FormatController
2632

2733
private lateinit var account: Account
2834

@@ -34,17 +40,30 @@ class AccountOperationsFragment : BaseFragment() {
3440
}
3541

3642
override fun initViews(view: View) {
37-
recyclerView.adapter = RecordAdapter(requireContext(), getRecords(), false, null)
43+
recyclerView.adapter = RecordAdapter(requireContext(), getRecordAdapterDataList(), false, null)
3844
}
3945

40-
private fun getRecords(): List<Record> {
46+
private fun getRecordAdapterDataList(): List<RecordAdapterData> {
4147
val accountRecords = recordController.getRecordsForAccount(account)
4248
val accountTransfers = transferController.getTransfersForAccount(account)
4349

4450
accountRecords += obtainRecordsFromTransfers(accountTransfers)
4551
accountRecords.sortByDescending { it.time }
4652

47-
return accountRecords
53+
val recordAdapterData: MutableList<RecordAdapterData> = mutableListOf()
54+
55+
var lastDate = EMPTY_DATE
56+
57+
for (record in accountRecords) {
58+
if (formatController.formatDateToString(record.time) != lastDate) {
59+
lastDate = formatController.formatDateToString(record.time)
60+
recordAdapterData.add(HeaderItem(lastDate))
61+
}
62+
63+
recordAdapterData.add(RecordItem(record))
64+
}
65+
66+
return recordAdapterData
4867
}
4968

5069
private fun obtainRecordsFromTransfers(transfers: List<Transfer>): List<Record> {
@@ -73,6 +92,7 @@ class AccountOperationsFragment : BaseFragment() {
7392
companion object {
7493

7594
private const val KEY_ACCOUNT = "key_account"
95+
private const val EMPTY_DATE = "empty_date"
7696

7797
fun newInstance(account: Account): AccountOperationsFragment {
7898
val fragment = AccountOperationsFragment()

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: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import com.blogspot.e_kanivets.moneytracker.controller.PreferenceController
1414
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
17+
import com.blogspot.e_kanivets.moneytracker.entity.RecordAdapterData
18+
import com.blogspot.e_kanivets.moneytracker.entity.HeaderItem
1719
import com.blogspot.e_kanivets.moneytracker.entity.Period
20+
import com.blogspot.e_kanivets.moneytracker.entity.RecordItem
1821
import com.blogspot.e_kanivets.moneytracker.entity.data.Record
1922
import com.blogspot.e_kanivets.moneytracker.report.ReportMaker
2023
import com.blogspot.e_kanivets.moneytracker.ui.AppRateDialog
@@ -26,6 +29,7 @@ import javax.inject.Inject
2629
class MainActivity : BaseDrawerActivity() {
2730

2831
private lateinit var recordList: List<Record>
32+
private val recordAdapterDataList: MutableList<RecordAdapterData> = mutableListOf()
2933
private lateinit var period: Period
3034
private lateinit var recordAdapter: RecordAdapter
3135

@@ -91,8 +95,7 @@ class MainActivity : BaseDrawerActivity() {
9195
private fun editRecord(position: Int) {
9296
AnswersProxy.get().logButton("Edit Record")
9397

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

@@ -134,17 +137,43 @@ class MainActivity : BaseDrawerActivity() {
134137
override fun update() {
135138
recordList = recordController.getRecordsForPeriod(period)
136139
recordList = recordList.reversed()
140+
updateRecordAdapterDataList()
137141

138142
val currency = currencyController.readDefaultCurrency()
139143

140144
val reportMaker = ReportMaker(rateController)
141145
val report = reportMaker.getRecordReport(currency, period, recordList)
142146

143-
recordAdapter.setRecords(recordList, report, currency, reportMaker.currencyNeeded(currency, recordList))
147+
recordAdapter.setRecords(recordAdapterDataList, report, currency, reportMaker.currencyNeeded(currency, recordList))
144148

145149
fillDefaultAccount()
146150
}
147151

152+
private fun getCountHeadersItems(position: Int): Int {
153+
var countHeadersItems = 0
154+
for (inOfData in 0 until position) {
155+
if (recordAdapterDataList[inOfData] is HeaderItem) {
156+
countHeadersItems++
157+
}
158+
}
159+
return countHeadersItems
160+
}
161+
162+
private fun updateRecordAdapterDataList() {
163+
recordAdapterDataList.clear()
164+
165+
var lastDate = EMPTY_DATE
166+
for (record in recordList) {
167+
if (formatController.formatDateToString(record.time) != lastDate) {
168+
lastDate = formatController.formatDateToString(record.time)
169+
recordAdapterDataList.add(HeaderItem(lastDate))
170+
}
171+
172+
recordAdapterDataList.add(RecordItem(record))
173+
}
174+
}
175+
176+
148177
private fun showAppRateDialog() {
149178
AnswersProxy.get().logEvent("Show App Rate Dialog")
150179
val dialog = AppRateDialog(this)
@@ -170,6 +199,7 @@ class MainActivity : BaseDrawerActivity() {
170199

171200
companion object {
172201
private const val REQUEST_ACTION_RECORD = 6
202+
private const val EMPTY_DATE = "empty_date"
173203
}
174204

175205
}

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

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ 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.RecordAdapterData
15+
import com.blogspot.e_kanivets.moneytracker.entity.HeaderItem
16+
import com.blogspot.e_kanivets.moneytracker.entity.RecordItem
1517
import com.blogspot.e_kanivets.moneytracker.report.record.IRecordReport
1618
import com.blogspot.e_kanivets.moneytracker.ui.presenter.ShortSummaryPresenter
19+
import kotlinx.android.synthetic.main.view_header_date.view.*
1720
import kotlinx.android.synthetic.main.view_record.view.*
21+
import kotlinx.android.synthetic.main.view_record.view.container
1822
import kotlinx.android.synthetic.main.view_summary_records.view.*
1923
import javax.inject.Inject
2024

@@ -30,16 +34,16 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
3034
private var red: Int
3135
private var green: Int
3236

33-
private var records: List<Record>
37+
private var items: List<RecordAdapterData>
3438
private var context: Context
3539

3640
private var summaryPresenter: ShortSummaryPresenter
37-
private var isHeaderViewNeeded: Boolean = false
38-
private var headerViewHolder: HeaderViewHolder
41+
private var isSummaryViewNeeded: Boolean = false
42+
private var summaryViewHolder: SummaryViewHolder
3943

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

4448
MtApp.get().appComponent.inject(this)
4549

@@ -51,68 +55,71 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
5155
summaryPresenter = ShortSummaryPresenter(context)
5256

5357
this.itemClickListener = itemClickListener
54-
this.isHeaderViewNeeded = isHeaderViewNeeded
58+
this.isSummaryViewNeeded = isSummaryViewNeeded
5559

56-
headerViewHolder = HeaderViewHolder(LayoutInflater.from(context).inflate(R.layout.view_summary_records, null), itemClickListener)
57-
summaryPresenter.create(true, headerViewHolder)
60+
summaryViewHolder = SummaryViewHolder(LayoutInflater.from(context).inflate(R.layout.view_summary_records, null), itemClickListener)
61+
summaryPresenter.create(true, summaryViewHolder)
5862
}
5963

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

62-
override fun getItemViewType(position: Int): Int = if (position == 0 && isHeaderViewNeeded) {
66+
override fun getItemViewType(position: Int): Int = if (position == 0 && isSummaryViewNeeded) {
67+
TYPE_SUMMARY
68+
} else if (items[position - if (isSummaryViewNeeded) 1 else 0] is HeaderItem) {
6369
TYPE_HEADER
6470
} else {
65-
TYPE_ITEM
71+
TYPE_RECORD
6672
}
6773

6874
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)
75+
when (viewType) {
76+
TYPE_RECORD -> RecordViewHolder(LayoutInflater.from(context).inflate(R.layout.view_record, parent, false), itemClickListener)
77+
TYPE_HEADER -> HeaderViewHolder(LayoutInflater.from(context).inflate(R.layout.view_header_date, parent, false))
78+
else -> summaryViewHolder
7379
}
7480

7581
override fun onBindViewHolder(rvViewHolder: RecyclerView.ViewHolder, position: Int) {
76-
if (position == 0 && isHeaderViewNeeded) {
82+
if (position == 0 && isSummaryViewNeeded) {
7783
//adapter already bound to view
7884
return
7985
}
8086

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
87+
if (rvViewHolder is RecordViewHolder) {
88+
val record = items[position - if (isSummaryViewNeeded) 1 else 0] as RecordItem
89+
rvViewHolder.tvPrice.setTextColor(if (record.isIncome) green else red)
90+
91+
val price = (if (record.isIncome) record.fullPrice else getNegative(record.fullPrice))
92+
rvViewHolder.tvPrice.text = formatController.formatSignedAmount(price)
93+
rvViewHolder.tvTitle.text = record.title
94+
rvViewHolder.tvCategory.text = record.categoryName
95+
rvViewHolder.tvCurrency.text = record.currency
96+
} else {
97+
val headerViewHolder = rvViewHolder as HeaderViewHolder
98+
val header = items[position - if (isSummaryViewNeeded) 1 else 0] as HeaderItem
99+
headerViewHolder.tvDate.text = header.date
100+
}
92101
}
93102

94103
private fun getNegative(number: Double): Double {
95104
return -1 * number
96105
}
97106

98-
fun setRecords(recordsList: List<Record>, report: IRecordReport?, currency: String, ratesNeeded: List<String>) {
99-
records = recordsList
107+
fun setRecords(itemsList: List<RecordAdapterData>, report: IRecordReport?, currency: String, ratesNeeded: List<String>) {
108+
items = itemsList
100109
summaryPresenter.update(report, currency, ratesNeeded)
101110
notifyDataSetChanged()
102111
}
103112

104-
class ViewHolder : RecyclerView.ViewHolder {
113+
class RecordViewHolder : RecyclerView.ViewHolder {
105114

106115
var container: LinearLayout
107-
var tvDateAndTime: TextView
108116
var tvPrice: TextView
109117
var tvTitle: TextView
110118
var tvCategory: TextView
111119
var tvCurrency: TextView
112120

113121
constructor(view: View, itemClickListener: ((Int) -> Unit)?) : super(view) {
114122
container = view.container
115-
tvDateAndTime = view.tvDateAndTime
116123
tvPrice = view.tvPrice
117124
tvTitle = view.tvTitle
118125
tvCategory = view.tvCategory
@@ -124,7 +131,11 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
124131
}
125132
}
126133

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

129140
private var tvPeriod: TextView
130141
private var tvTotalIncome: TextView
@@ -145,15 +156,15 @@ class RecordAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder> {
145156
tvTotalExpense = view.tvTotalExpense
146157
tvTotal = view.tvTotal
147158

148-
view.setOnClickListener {
159+
view.cvSummary.setOnClickListener {
149160
itemClickListener?.invoke(0)
150161
}
151162
}
152163
}
153164

154165
companion object {
155-
156-
private const val TYPE_HEADER = 0
157-
private const val TYPE_ITEM = 1
166+
private const val TYPE_SUMMARY = 0
167+
private const val TYPE_HEADER = 1
168+
private const val TYPE_RECORD = 2
158169
}
159170
}

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 dateInNumberFormat = new SimpleDateFormat("yyyy-MM-dd");
24+
@SuppressLint("SimpleDateFormat")
25+
private static final SimpleDateFormat dateInStringFormat = 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 dateInNumberFormat.format(new Date(timestamp));
79+
}
80+
81+
public String formatDateToString(long timestamp) {
82+
return dateInStringFormat.format(new Date(timestamp));
7783
}
7884

7985
public String formatTime(long timestamp) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,15 @@ public Period yearPeriod() {
133133
public Period allTimePeriod() {
134134
Calendar cal = Calendar.getInstance();
135135

136-
// set start of time by Jesus
136+
// set start of date by Jesus
137137
cal.set(Calendar.YEAR, 2000);
138138
cal.set(Calendar.MONTH, Calendar.JANUARY);
139139
cal.set(Calendar.DAY_OF_MONTH, 1);
140140
setDayStart(cal);
141141

142142
Date first = cal.getTime();
143143

144-
// set possible end of time
144+
// set possible end of date
145145
cal.set(Calendar.YEAR, 3000);
146146
cal.set(Calendar.MONTH, Calendar.DECEMBER);
147147
cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));

app/src/main/java/com/blogspot/e_kanivets/moneytracker/controller/data/RecordController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ record = validateRecord(record);
9292
@NonNull @Override public List<Record> readWithCondition(String condition, String[] args) {
9393
List<Record> recordList = super.readWithCondition(condition, args);
9494

95-
// Sort record list by time field from smallest to biggest
95+
// Sort record list by date field from smallest to biggest
9696
Collections.sort(recordList, new Comparator<Record>() {
9797
@Override public int compare(Record lhs, Record rhs) {
9898
return lhs.getTime() < rhs.getTime() ? -1 : (lhs.getTime() == rhs.getTime() ? 0 : 1);

app/src/main/java/com/blogspot/e_kanivets/moneytracker/controller/external/Head.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @author Evgenii Kanivets
88
*/
99
public interface Head {
10-
String TIME = "time";
10+
String TIME = "date";
1111
String TITLE = "title";
1212
String CATEGORY = "category";
1313
String PRICE = "price";

0 commit comments

Comments
 (0)