From 7c0a7b8a6c14a7a3793047c9d24b8c81a1352946 Mon Sep 17 00:00:00 2001 From: Mantas Varnagiris Date: Mon, 22 May 2017 21:30:58 +0100 Subject: [PATCH 1/9] Prepared for dev. --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8a60d0af..c39818db 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,8 +43,8 @@ android { minSdkVersion min_sdk_version targetSdkVersion target_sdk_version multiDexEnabled true - versionCode 14 - versionName "0.5.4" + versionCode 15 + versionName "0.5.5" manifestPlaceholders = [crashlytics: privateProperties['CRASHLYTICS']] } From 2dc42205944ec468cd55beabd5df8ee7c194b817 Mon Sep 17 00:00:00 2001 From: Mantas Varnagiris Date: Mon, 22 May 2017 21:33:30 +0100 Subject: [PATCH 2/9] Upgradle. --- app/build.gradle | 2 +- build.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c39818db..829370ec 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,7 +17,7 @@ buildscript { maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'io.fabric.tools:gradle:1.21.6' + classpath 'io.fabric.tools:gradle:1.22.1' } } diff --git a/build.gradle b/build.gradle index 47217455..1628d1f5 100644 --- a/build.gradle +++ b/build.gradle @@ -19,8 +19,8 @@ buildscript { ext.junit_version = '4.12' ext.mockito_kotlin_version = '1.1.0' ext.support_version = '25.3.1' - ext.rxbinding_version = '0.4.0' - ext.firebase_version = '10.2.0' + ext.rxbinding_version = '1.0.0' + ext.firebase_version = '10.2.6' ext.hamkrest_version = '1.2.1.0' ext.assertk_version = '0.1.1' ext.build_tools_version = '25.0.2' From 86c1844562004b8902b35dd675306a6523333848 Mon Sep 17 00:00:00 2001 From: Mantas Varnagiris Date: Tue, 23 May 2017 12:41:50 +0100 Subject: [PATCH 3/9] Showing empty state in transactions. --- .../transaction/TransactionsPresenter.kt | 20 +++++++--------- .../transaction/TransactionsPresenterTest.kt | 24 +++++++++++++++---- .../transaction/TransactionsActivity.kt | 9 ++++--- .../main/res/layout/activity_transactions.xml | 9 +++++++ build.gradle | 1 + 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/app-core/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenter.kt b/app-core/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenter.kt index 637ab484..f0299221 100644 --- a/app-core/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenter.kt +++ b/app-core/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenter.kt @@ -17,9 +17,7 @@ package com.mvcoding.expensius.feature.transaction import com.mvcoding.expensius.RxSchedulers import com.mvcoding.expensius.data.DataSource import com.mvcoding.expensius.data.RealtimeData -import com.mvcoding.expensius.feature.LoadingView -import com.mvcoding.expensius.feature.ModelDisplayType -import com.mvcoding.expensius.feature.RealtimeItemsView +import com.mvcoding.expensius.feature.* import com.mvcoding.expensius.model.Transaction import com.mvcoding.mvp.Presenter import rx.Observable @@ -40,13 +38,13 @@ class TransactionsPresenter( .subscribeOn(schedulers.io) .observeOn(schedulers.main) .doOnNext { view.hideLoading() } - .subscribeUntilDetached { - when (it) { - is RealtimeData.AllItems -> view.showItems(it.allItems) - is RealtimeData.AddedItems -> view.showAddedItems(it.addedItems, it.position) - is RealtimeData.ChangedItems -> view.showChangedItems(it.changedItems, it.position) - is RealtimeData.RemovedItems -> view.showRemovedItems(it.removedItems, it.position) - is RealtimeData.MovedItems -> view.showMovedItems(it.movedItems, it.fromPosition, it.toPosition) + .subscribeUntilDetached { realtimeData -> + when (realtimeData) { + is RealtimeData.AllItems -> view.showItems(realtimeData.allItems).also { view.updateEmptyView(realtimeData.allItems) } + is RealtimeData.AddedItems -> view.showAddedItems(realtimeData.addedItems, realtimeData.position) + is RealtimeData.ChangedItems -> view.showChangedItems(realtimeData.changedItems, realtimeData.position) + is RealtimeData.RemovedItems -> view.showRemovedItems(realtimeData.removedItems, realtimeData.position).also { view.updateEmptyView(realtimeData.allItems) } + is RealtimeData.MovedItems -> view.showMovedItems(realtimeData.movedItems, realtimeData.fromPosition, realtimeData.toPosition) } } @@ -55,7 +53,7 @@ class TransactionsPresenter( view.archivedTransactionsRequests().subscribeUntilDetached { view.displayArchivedTransactions() } } - interface View : Presenter.View, RealtimeItemsView, LoadingView { + interface View : Presenter.View, RealtimeItemsView, LoadingView, EmptyView { fun transactionSelects(): Observable fun createTransactionRequests(): Observable fun archivedTransactionsRequests(): Observable diff --git a/app-core/src/test/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenterTest.kt b/app-core/src/test/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenterTest.kt index f95ddc70..f13fb3e3 100644 --- a/app-core/src/test/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenterTest.kt +++ b/app-core/src/test/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsPresenterTest.kt @@ -97,6 +97,20 @@ class TransactionsPresenterTest { inOrder.verify(view).showMovedItems(movedTransactions, 0, 5) } + @Test + fun `shows empty when there are no transactions`() { + presenter().attach(view) + + receiveTransactions(emptyList()) + inOrder.verify(view).showEmptyView() + + receiveTransactions(someTransactions()) + inOrder.verify(view).hideEmptyView() + + receiveTransactionsRemoved(emptyList(), 0) + inOrder.verify(view).showEmptyView() + } + @Test fun `displays transaction edit when selecting a transaction and display type is view`() { val transaction = aTransaction() @@ -125,13 +139,13 @@ class TransactionsPresenterTest { verify(view).displayArchivedTransactions() } - private fun receiveTransactions(tags: List) = transactionsSubject.onNext(RealtimeData.AllItems(tags)) + private fun receiveTransactions(transactions: List) = transactionsSubject.onNext(RealtimeData.AllItems(transactions)) private fun requestCreateTransaction() = createTransactionRequestsSubject.onNext(Unit) private fun requestArchivedTransactions() = displayArchivedTransactionsSubject.onNext(Unit) - private fun receiveTransactionsAdded(tags: List, position: Int) = transactionsSubject.onNext(RealtimeData.AddedItems(tags, tags, position)) - private fun receiveTransactionsChanged(tags: List, position: Int) = transactionsSubject.onNext(RealtimeData.ChangedItems(tags, tags, position)) - private fun receiveTransactionsRemoved(tags: List, position: Int) = transactionsSubject.onNext(RealtimeData.RemovedItems(tags, tags, position)) - private fun receiveTransactionsMoved(tags: List, fromPosition: Int, toPosition: Int) = transactionsSubject.onNext(RealtimeData.MovedItems(tags, tags, fromPosition, toPosition)) + private fun receiveTransactionsAdded(transactions: List, position: Int) = transactionsSubject.onNext(RealtimeData.AddedItems(transactions, transactions, position)) + private fun receiveTransactionsChanged(transactions: List, position: Int) = transactionsSubject.onNext(RealtimeData.ChangedItems(transactions, transactions, position)) + private fun receiveTransactionsRemoved(transactions: List, position: Int) = transactionsSubject.onNext(RealtimeData.RemovedItems(transactions, transactions, position)) + private fun receiveTransactionsMoved(transactions: List, fromPosition: Int, toPosition: Int) = transactionsSubject.onNext(RealtimeData.MovedItems(transactions, transactions, fromPosition, toPosition)) private fun selectTransaction(transaction: Transaction) = transactionSelectsSubject.onNext(transaction) private fun presenter(modelViewType: ModelDisplayType = VIEW_NOT_ARCHIVED) = TransactionsPresenter(modelViewType, transactionsSource, rxSchedulers()) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt b/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt index ab2aec27..6dda3387 100644 --- a/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt +++ b/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt @@ -17,10 +17,11 @@ package com.mvcoding.expensius.feature.transaction import android.content.Context import android.os.Bundle import android.support.v7.widget.LinearLayoutManager -import android.view.View import com.jakewharton.rxbinding.view.clicks import com.mvcoding.expensius.R import com.mvcoding.expensius.extension.getColorFromTheme +import com.mvcoding.expensius.extension.setGone +import com.mvcoding.expensius.extension.setVisible import com.mvcoding.expensius.feature.ActivityStarter import com.mvcoding.expensius.feature.BaseActivity import com.mvcoding.expensius.feature.DividerItemDecoration @@ -83,8 +84,10 @@ class TransactionsActivity : BaseActivity(), TransactionsPresenter.View { override fun showChangedItems(items: List, position: Int): Unit = adapter.changeItems(position, items) override fun showRemovedItems(items: List, position: Int): Unit = adapter.removeItems(position, items.size) override fun showMovedItems(items: List, fromPosition: Int, toPosition: Int): Unit = adapter.moveItem(fromPosition, toPosition) - override fun showLoading(): Unit = with(progressBar) { visibility = View.VISIBLE } - override fun hideLoading(): Unit = with(progressBar) { visibility = View.GONE } + override fun showLoading(): Unit = progressBar.setVisible() + override fun hideLoading(): Unit = progressBar.setGone() + override fun showEmptyView(): Unit = emptyTextView.setVisible() + override fun hideEmptyView(): Unit = emptyTextView.setGone() override fun displayTransactionEdit(transaction: Transaction): Unit = TransactionActivity.start(this, transaction) override fun displayCalculator(): Unit = CalculatorActivity.start(this) override fun displayArchivedTransactions(): Unit = TransactionsActivity.startArchived(this) diff --git a/app/src/main/res/layout/activity_transactions.xml b/app/src/main/res/layout/activity_transactions.xml index ddf4c9a6..5b12c3fe 100644 --- a/app/src/main/res/layout/activity_transactions.xml +++ b/app/src/main/res/layout/activity_transactions.xml @@ -42,6 +42,15 @@ android:id="@+id/progressBar" style="@style/ProgressBar" /> + + Date: Tue, 23 May 2017 12:56:26 +0100 Subject: [PATCH 4/9] Showing archived transactions. --- .../transaction/TransactionsActivity.kt | 17 ++++++++++--- .../main/res/drawable/ic_action_archive.xml | 16 ++++++++++++- app/src/main/res/menu/transactions.xml | 24 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 app/src/main/res/menu/transactions.xml diff --git a/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt b/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt index 6dda3387..1571fa8a 100644 --- a/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt +++ b/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsActivity.kt @@ -17,6 +17,8 @@ package com.mvcoding.expensius.feature.transaction import android.content.Context import android.os.Bundle import android.support.v7.widget.LinearLayoutManager +import android.view.Menu +import com.jakewharton.rxbinding.support.v7.widget.itemClicks import com.jakewharton.rxbinding.view.clicks import com.mvcoding.expensius.R import com.mvcoding.expensius.extension.getColorFromTheme @@ -31,8 +33,8 @@ import com.mvcoding.expensius.feature.ModelDisplayType.VIEW_NOT_ARCHIVED import com.mvcoding.expensius.feature.calculator.CalculatorActivity import com.mvcoding.expensius.model.Transaction import kotlinx.android.synthetic.main.activity_transactions.* +import kotlinx.android.synthetic.main.toolbar.* import rx.Observable -import rx.Observable.empty class TransactionsActivity : BaseActivity(), TransactionsPresenter.View { @@ -50,6 +52,7 @@ class TransactionsActivity : BaseActivity(), TransactionsPresenter.View { private val presenter by lazy { provideTransactionsPresenter(intent.getSerializableExtra(EXTRA_DISPLAY_TYPE) as ModelDisplayType) } private val adapter by lazy { TransactionsAdapter() } + private var showArchivedTransactionsAction = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -68,16 +71,24 @@ class TransactionsActivity : BaseActivity(), TransactionsPresenter.View { super.onDestroy() } + override fun onCreateOptionsMenu(menu: Menu): Boolean { + super.onCreateOptionsMenu(menu) + menuInflater.inflate(R.menu.transactions, menu) + menu.findItem(R.id.action_archived_transactions).isVisible = showArchivedTransactionsAction + return true + } + override fun showModelDisplayType(modelDisplayType: ModelDisplayType) { supportActionBar?.title = if (modelDisplayType == VIEW_ARCHIVED) getString(R.string.archived_transactions) else getString(R.string.transactions) } override fun showArchivedTransactionsRequest() { - + showArchivedTransactionsAction = true + supportInvalidateOptionsMenu() } override fun transactionSelects(): Observable = adapter.itemClicks() - override fun archivedTransactionsRequests(): Observable = empty() + override fun archivedTransactionsRequests(): Observable = toolbar.itemClicks().filter { it.itemId == R.id.action_archived_transactions }.map { Unit } override fun createTransactionRequests(): Observable = createTransactionButton.clicks() override fun showItems(items: List): Unit = adapter.setItems(items) override fun showAddedItems(items: List, position: Int): Unit = adapter.addItems(position, items) diff --git a/app/src/main/res/drawable/ic_action_archive.xml b/app/src/main/res/drawable/ic_action_archive.xml index 0c90aa5b..b001fe47 100644 --- a/app/src/main/res/drawable/ic_action_archive.xml +++ b/app/src/main/res/drawable/ic_action_archive.xml @@ -1,3 +1,17 @@ + + + android:pathData="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-0.47 0-0.88 0.21-1.16 0.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1 0.9 2 2 2h14c1.1 0 2-0.9 2-2V6.5c0-0.48-0.17-0.93-0.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l0.81-1h12l0.94 1H5.12z" /> \ No newline at end of file diff --git a/app/src/main/res/menu/transactions.xml b/app/src/main/res/menu/transactions.xml new file mode 100644 index 00000000..e47e2154 --- /dev/null +++ b/app/src/main/res/menu/transactions.xml @@ -0,0 +1,24 @@ + + + + + + + \ No newline at end of file From 8ddeccea44ec036a1b5157e8ff7ae1bb7b1a9cc0 Mon Sep 17 00:00:00 2001 From: Mantas Varnagiris Date: Tue, 23 May 2017 13:02:17 +0100 Subject: [PATCH 5/9] Correctly formatting yesterday and tomorrow. --- .../expensius/extension/JodaTimeExtensions.kt | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/com/mvcoding/expensius/extension/JodaTimeExtensions.kt b/app/src/main/kotlin/com/mvcoding/expensius/extension/JodaTimeExtensions.kt index ed4c19e8..8d8f5e20 100644 --- a/app/src/main/kotlin/com/mvcoding/expensius/extension/JodaTimeExtensions.kt +++ b/app/src/main/kotlin/com/mvcoding/expensius/extension/JodaTimeExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Mantas Varnagiris. + * Copyright (C) 2017 Mantas Varnagiris. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,14 +14,9 @@ package com.mvcoding.expensius.extension +import android.text.format.DateUtils +import org.joda.time.LocalDate import org.joda.time.ReadableInstant -fun isYesterday(readableInstant: ReadableInstant): Boolean { - // TODO Implement - return false -} - -fun isTomorrow(readableInstant: ReadableInstant): Boolean { - // TODO Implement - return false -} \ No newline at end of file +fun isYesterday(readableInstant: ReadableInstant): Boolean = LocalDate.now().compareTo(LocalDate(readableInstant.millis + DateUtils.DAY_IN_MILLIS)) == 0 +fun isTomorrow(readableInstant: ReadableInstant): Boolean = LocalDate.now().compareTo(LocalDate(readableInstant.millis - DateUtils.DAY_IN_MILLIS)) == 0 \ No newline at end of file From 2aaa622e3459065af0c71204c7c3960ea2f93648 Mon Sep 17 00:00:00 2001 From: Mantas Varnagiris Date: Tue, 23 May 2017 14:52:10 +0100 Subject: [PATCH 6/9] Date now includes year. --- .../expensius/feature/DateFormatter.kt | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/com/mvcoding/expensius/feature/DateFormatter.kt b/app/src/main/kotlin/com/mvcoding/expensius/feature/DateFormatter.kt index 4b7240dd..b084650f 100644 --- a/app/src/main/kotlin/com/mvcoding/expensius/feature/DateFormatter.kt +++ b/app/src/main/kotlin/com/mvcoding/expensius/feature/DateFormatter.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016 Mantas Varnagiris. + * Copyright (C) 2017 Mantas Varnagiris. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,15 +19,20 @@ import com.mvcoding.expensius.R import com.mvcoding.expensius.extension.isTomorrow import com.mvcoding.expensius.extension.isYesterday import com.mvcoding.expensius.model.ReportPeriod -import net.danlew.android.joda.DateUtils.FORMAT_ABBREV_ALL -import net.danlew.android.joda.DateUtils.FORMAT_SHOW_DATE -import net.danlew.android.joda.DateUtils.FORMAT_SHOW_WEEKDAY -import net.danlew.android.joda.DateUtils.formatDateTime -import net.danlew.android.joda.DateUtils.isToday +import net.danlew.android.joda.DateUtils.* import org.joda.time.DateTime import org.joda.time.Interval +import org.joda.time.format.DateTimeFormatter +import org.joda.time.format.DateTimeFormatterBuilder class DateFormatter(private val context: Context) { + + val dateFormatter: DateTimeFormatter = DateTimeFormatterBuilder() + .appendMonthOfYearText() + .appendLiteral(" ") + .appendYear(0, 4) + .toFormatter() + fun formatDateRelativeToToday(timestamp: Long): String { val dateTime = DateTime(timestamp) @@ -43,5 +48,7 @@ class DateFormatter(private val context: Context) { } fun formatDateShort(dateTime: DateTime): String = formatDateTime(context, dateTime, FORMAT_SHOW_DATE or FORMAT_ABBREV_ALL) - fun formatInterval(reportPeriod: ReportPeriod, interval: Interval): String = interval.start.monthOfYear().asText + fun formatInterval(reportPeriod: ReportPeriod, interval: Interval): String = when (reportPeriod) { + ReportPeriod.MONTH -> dateFormatter.print(interval.start) + } } \ No newline at end of file From dac4010faedcc0db80723b9dfcff55bce4b7e444 Mon Sep 17 00:00:00 2001 From: Mantas Varnagiris Date: Tue, 23 May 2017 14:54:41 +0100 Subject: [PATCH 7/9] Updated changelog and version name. --- CHANGELOG.md | 6 ++++++ app/build.gradle | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ca5c7a1..2376d516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### v0.6.0 +- `new` Date formatting now includes year. +- `new` Added empty state for transactions screen. +- `new` Added ability to view and restore archived transactions. +- `new` Showing *Yesterday* and *Tomorrow* for days around *Today*. + ### v0.5.4 - `fix` This time for real fixed billing crash. Maybe. diff --git a/app/build.gradle b/app/build.gradle index 829370ec..561f9bb0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,7 +44,7 @@ android { targetSdkVersion target_sdk_version multiDexEnabled true versionCode 15 - versionName "0.5.5" + versionName "0.6.0" manifestPlaceholders = [crashlytics: privateProperties['CRASHLYTICS']] } From 15b4de7a29b9c9fffcae0afb71064d71a7711f86 Mon Sep 17 00:00:00 2001 From: Mantas Varnagiris Date: Tue, 23 May 2017 17:24:56 +0100 Subject: [PATCH 8/9] Added empty state for tags report. --- CHANGELOG.md | 1 + .../reports/tags/TagsReportPresenter.kt | 9 +++- .../reports/tags/TagsReportPresenterTest.kt | 23 +++++++-- .../feature/overview/OverviewActivity.kt | 2 + .../reports/tags/TagsReportOverviewView.kt | 27 ++++++++++ .../feature/reports/tags/TagsReportView.kt | 50 ++++++++++++++----- .../transaction/TransactionsOverviewView.kt | 4 ++ app/src/main/res/layout/activity_overview.xml | 6 +-- .../main/res/layout/activity_tags_report.xml | 36 ++++++------- app/src/main/res/layout/view_tags_report.xml | 35 +++++++++++++ .../res/layout/view_tags_report_overview.xml | 16 +++--- .../res/layout/view_transactions_overview.xml | 3 +- .../model/extensions/TagsReportExtensions.kt | 4 +- 13 files changed, 159 insertions(+), 57 deletions(-) create mode 100644 app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportOverviewView.kt create mode 100644 app/src/main/res/layout/view_tags_report.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 2376d516..2affd6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - `new` Added empty state for transactions screen. - `new` Added ability to view and restore archived transactions. - `new` Showing *Yesterday* and *Tomorrow* for days around *Today*. +- `new` Added empty state for tags report. ### v0.5.4 - `fix` This time for real fixed billing crash. Maybe. diff --git a/app-core/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenter.kt b/app-core/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenter.kt index fffc87e7..3d1dd433 100644 --- a/app-core/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenter.kt +++ b/app-core/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenter.kt @@ -17,7 +17,9 @@ package com.mvcoding.expensius.feature.reports.tags import com.mvcoding.expensius.RxSchedulers import com.mvcoding.expensius.data.Cache import com.mvcoding.expensius.data.DataSource +import com.mvcoding.expensius.feature.EmptyView import com.mvcoding.expensius.feature.ignoreError +import com.mvcoding.expensius.feature.updateEmptyView import com.mvcoding.expensius.model.RemoteFilter import com.mvcoding.expensius.model.ReportSettings import com.mvcoding.expensius.model.TagsReport @@ -43,10 +45,13 @@ class TagsReportPresenter( .subscribeOn(schedulers.io) .observeOn(schedulers.main) .ignoreError() - .subscribeUntilDetached { view.showTagsReport(it) } + .subscribeUntilDetached { + view.showTagsReport(it) + view.updateEmptyView(it.currentMoneys) + } } - interface View : Presenter.View { + interface View : Presenter.View, EmptyView { fun showTagsReport(tagsReport: TagsReport) } } \ No newline at end of file diff --git a/app-core/src/test/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenterTest.kt b/app-core/src/test/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenterTest.kt index f78878be..9950fcc5 100644 --- a/app-core/src/test/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenterTest.kt +++ b/app-core/src/test/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportPresenterTest.kt @@ -22,11 +22,13 @@ import com.mvcoding.expensius.model.TagsReport import com.mvcoding.expensius.model.extensions.aRemoteFilter import com.mvcoding.expensius.model.extensions.aReportSettings import com.mvcoding.expensius.model.extensions.aTagsReport +import com.mvcoding.expensius.model.extensions.empty import com.mvcoding.expensius.rxSchedulers import com.nhaarman.mockito_kotlin.* import org.junit.Before import org.junit.Test -import rx.Observable +import rx.Observable.error +import rx.Observable.just class TagsReportPresenterTest { val tagsReport = aTagsReport() @@ -34,14 +36,14 @@ class TagsReportPresenterTest { val remoteFilter = aRemoteFilter(reportSettings.reportPeriod) val tagsReportSource = mock>() - val reportSettingsSource = mock>().apply { whenever(data()).thenReturn(Observable.just(reportSettings)) } - val secondaryRemoteFilterCache = mock>().apply { whenever(data()).thenReturn(Observable.just(remoteFilter)) } + val reportSettingsSource = mock>().apply { whenever(data()).thenReturn(just(reportSettings)) } + val secondaryRemoteFilterCache = mock>().apply { whenever(data()).thenReturn(just(remoteFilter)) } val view = mock() val presenter = TagsReportPresenter(tagsReportSource, reportSettingsSource, secondaryRemoteFilterCache, rxSchedulers()) @Before fun setUp() { - whenever(tagsReportSource.data()).thenReturn(Observable.just(tagsReport)) + whenever(tagsReportSource.data()).thenReturn(just(tagsReport)) } @Test @@ -54,11 +56,22 @@ class TagsReportPresenterTest { presenter.attach(view) verify(view).showTagsReport(tagsReport) + verify(view).hideEmptyView() + } + + @Test + fun `shows empty view when report is empty`() { + val emptyTagsReport = tagsReport.empty() + whenever(tagsReportSource.data()).thenReturn(just(emptyTagsReport)) + presenter.attach(view) + + verify(view).showTagsReport(emptyTagsReport) + verify(view).showEmptyView() } @Test fun `ignores errors`() { - whenever(tagsReportSource.data()).thenReturn(Observable.error(Throwable())) + whenever(tagsReportSource.data()).thenReturn(error(Throwable())) presenter.attach(view) diff --git a/app/src/main/kotlin/com/mvcoding/expensius/feature/overview/OverviewActivity.kt b/app/src/main/kotlin/com/mvcoding/expensius/feature/overview/OverviewActivity.kt index 415a286f..4552d6f1 100644 --- a/app/src/main/kotlin/com/mvcoding/expensius/feature/overview/OverviewActivity.kt +++ b/app/src/main/kotlin/com/mvcoding/expensius/feature/overview/OverviewActivity.kt @@ -33,6 +33,7 @@ import com.mvcoding.expensius.model.ReportPeriod import com.mvcoding.expensius.provideDateFormatter import kotlinx.android.synthetic.main.activity_overview.* import kotlinx.android.synthetic.main.toolbar.* +import kotlinx.android.synthetic.main.view_tags_report.* import kotlinx.android.synthetic.main.view_tags_report_overview.* import kotlinx.android.synthetic.main.view_transactions_overview.* import kotlinx.android.synthetic.main.view_trend_report.* @@ -54,6 +55,7 @@ class OverviewActivity : BaseActivity(), OverviewPresenter.View { setContentView(R.layout.activity_overview) removeUpArrowFromToolbar() presenter.attach(this) + tagsReportView.isEnabled = false } override fun onDestroy() { diff --git a/app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportOverviewView.kt b/app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportOverviewView.kt new file mode 100644 index 00000000..584ecebb --- /dev/null +++ b/app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportOverviewView.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 Mantas Varnagiris. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +package com.mvcoding.expensius.feature.reports.tags + +import android.content.Context +import android.util.AttributeSet +import android.widget.LinearLayout + +class TagsReportOverviewView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + LinearLayout(context, attrs, defStyleAttr) { + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportView.kt b/app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportView.kt index 9acf0d4b..8b1625b0 100644 --- a/app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportView.kt +++ b/app/src/main/kotlin/com/mvcoding/expensius/feature/reports/tags/TagsReportView.kt @@ -15,22 +15,38 @@ package com.mvcoding.expensius.feature.reports.tags import android.content.Context +import android.support.v7.widget.LinearLayoutManager import android.util.AttributeSet -import android.widget.LinearLayout +import android.view.MotionEvent +import android.view.ViewGroup +import android.widget.FrameLayout import com.mvcoding.expensius.extension.doNotInEditMode +import com.mvcoding.expensius.extension.setGone +import com.mvcoding.expensius.extension.setVisible +import com.mvcoding.expensius.feature.BaseAdapter +import com.mvcoding.expensius.feature.ViewHolder import com.mvcoding.expensius.feature.reports.provideTagsReportPresenter +import com.mvcoding.expensius.model.GroupedMoney import com.mvcoding.expensius.model.NullModels.noMoney +import com.mvcoding.expensius.model.Tag import com.mvcoding.expensius.model.TagsReport +import kotlinx.android.synthetic.main.view_tags_report.view.* +import java.math.BigDecimal class TagsReportView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : - LinearLayout(context, attrs, defStyleAttr), TagsReportPresenter.View { + FrameLayout(context, attrs, defStyleAttr), TagsReportPresenter.View { private val presenter by lazy { provideTagsReportPresenter() } + private val adapter by lazy { Adapter() } - init { - orientation = VERTICAL + override fun onFinishInflate() { + super.onFinishInflate() + recyclerView.layoutManager = LinearLayoutManager(context) + recyclerView.adapter = adapter } + override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean = !isEnabled + override fun onAttachedToWindow() { super.onAttachedToWindow() doNotInEditMode { presenter.attach(this) } @@ -42,14 +58,24 @@ class TagsReportView @JvmOverloads constructor(context: Context, attrs: Attribut } override fun showTagsReport(tagsReport: TagsReport) { - removeAllViews() - val maxMoney = tagsReport.currentMoneys.firstOrNull()?.money ?: noMoney - tagsReport.currentMoneys.forEach { - val tagReportItemView = TagMoneyItemView.inflate(this) - addView(tagReportItemView) - tagReportItemView.setTag(it.group) - tagReportItemView.setMoney(it.money) - tagReportItemView.setProgress(it.money.amount.toFloat() / maxMoney.amount.toFloat()) + adapter.maxMoneyAmount = (tagsReport.currentMoneys.firstOrNull()?.money ?: noMoney).amount + adapter.setItems(tagsReport.currentMoneys) + } + + override fun showEmptyView(): Unit = emptyTextView.setVisible() + override fun hideEmptyView(): Unit = emptyTextView.setGone() + + private class Adapter : BaseAdapter, ViewHolder>() { + var maxMoneyAmount: BigDecimal = BigDecimal.ONE + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(TagMoneyItemView.inflate(parent)) + + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val view = holder.getView() + val item = getItem(position) + view.setTag(item.group) + view.setMoney(item.money) + view.setProgress(item.money.amount.toFloat() / maxMoneyAmount.toFloat()) } } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsOverviewView.kt b/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsOverviewView.kt index 9a58832e..40ed22d7 100644 --- a/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsOverviewView.kt +++ b/app/src/main/kotlin/com/mvcoding/expensius/feature/transaction/TransactionsOverviewView.kt @@ -39,6 +39,10 @@ class TransactionsOverviewView @JvmOverloads constructor(context: Context, attrs override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean = true + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)) + } + override fun onAttachedToWindow() { super.onAttachedToWindow() doNotInEditMode { presenter.attach(this) } diff --git a/app/src/main/res/layout/activity_overview.xml b/app/src/main/res/layout/activity_overview.xml index dfb70348..5ab2fff9 100644 --- a/app/src/main/res/layout/activity_overview.xml +++ b/app/src/main/res/layout/activity_overview.xml @@ -47,11 +47,7 @@ - + diff --git a/app/src/main/res/layout/activity_tags_report.xml b/app/src/main/res/layout/activity_tags_report.xml index 222fbb8a..844b3de1 100644 --- a/app/src/main/res/layout/activity_tags_report.xml +++ b/app/src/main/res/layout/activity_tags_report.xml @@ -12,33 +12,25 @@ ~ GNU General Public License for more details. --> - + android:layout_height="match_parent" + android:orientation="vertical"> - + + - - - - - - + android:background="?colorPrimary" + android:elevation="@dimen/elevation_appbar" + android:orientation="vertical" + android:theme="?themeInverse"> - + - + - + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/view_tags_report.xml b/app/src/main/res/layout/view_tags_report.xml new file mode 100644 index 00000000..b60e7758 --- /dev/null +++ b/app/src/main/res/layout/view_tags_report.xml @@ -0,0 +1,35 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_tags_report_overview.xml b/app/src/main/res/layout/view_tags_report_overview.xml index beb3e5aa..ba8dca28 100644 --- a/app/src/main/res/layout/view_tags_report_overview.xml +++ b/app/src/main/res/layout/view_tags_report_overview.xml @@ -12,10 +12,10 @@ ~ GNU General Public License for more details. --> - + android:layout_marginBottom="@dimen/grid_2x"> - + android:layout_height="wrap_content" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/view_transactions_overview.xml b/app/src/main/res/layout/view_transactions_overview.xml index 4354c763..9b47bf90 100644 --- a/app/src/main/res/layout/view_transactions_overview.xml +++ b/app/src/main/res/layout/view_transactions_overview.xml @@ -16,7 +16,8 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/transactionsOverviewView" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/grid_2x" android:orientation="vertical"> Date: Tue, 23 May 2017 17:29:02 +0100 Subject: [PATCH 9/9] Some fixes to empty states. --- app/src/main/res/layout/activity_transactions.xml | 4 ++++ app/src/main/res/layout/view_tags_report.xml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/app/src/main/res/layout/activity_transactions.xml b/app/src/main/res/layout/activity_transactions.xml index 5b12c3fe..d81d5239 100644 --- a/app/src/main/res/layout/activity_transactions.xml +++ b/app/src/main/res/layout/activity_transactions.xml @@ -47,6 +47,10 @@ style="@style/TextView" android:layout_gravity="center" android:gravity="center" + android:paddingBottom="@dimen/grid_2x" + android:paddingLeft="@dimen/keyline" + android:paddingRight="@dimen/keyline" + android:paddingTop="@dimen/grid_2x" android:text="@string/empty_transactions" android:textAppearance="@style/Text.Title.Empty" android:visibility="gone" /> diff --git a/app/src/main/res/layout/view_tags_report.xml b/app/src/main/res/layout/view_tags_report.xml index b60e7758..cf503397 100644 --- a/app/src/main/res/layout/view_tags_report.xml +++ b/app/src/main/res/layout/view_tags_report.xml @@ -28,6 +28,10 @@ style="@style/TextView" android:layout_gravity="center" android:gravity="center" + android:paddingBottom="@dimen/grid_2x" + android:paddingLeft="@dimen/keyline" + android:paddingRight="@dimen/keyline" + android:paddingTop="@dimen/grid_2x" android:text="@string/empty_transactions" android:textAppearance="@style/Text.Title.Empty" android:visibility="gone" />