Implemented showing accounts and bank accounts hierarchically in Drawer

This commit is contained in:
dankito 2020-04-22 20:33:14 +02:00
parent 563afba3bc
commit 0699eaf977
13 changed files with 211 additions and 190 deletions

View File

@ -14,7 +14,9 @@ ext {
/* Android */
androidUtilsVersion = '1.1.0'
androidUtilsVersion = '1.1.1-SNAPSHOT'
materialDrawerVersion = "8.0.1"
clansFloatingActionButtonVersion = '1.6.4'

View File

@ -8,7 +8,7 @@ android {
defaultConfig {
applicationId "net.dankito.banking.fints4java.android"
minSdkVersion 15
minSdkVersion 16
targetSdkVersion 28
versionCode appVersionCode
versionName appVersionName
@ -77,6 +77,14 @@ dependencies {
implementation "com.google.android.material:material:$materialComponentsVersion"
implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"
// for MaterialDrawer
implementation "com.mikepenz:materialdrawer:$materialDrawerVersion"
implementation "com.mikepenz:materialdrawer-nav:$materialDrawerVersion"
implementation "com.mikepenz:materialdrawer-iconics:$materialDrawerVersion"
implementation "com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar"
implementation "com.mikepenz:fontawesome-typeface:5.9.0.0-kotlin@aar"
implementation 'androidx.navigation:navigation-fragment:2.0.0-rc02'
implementation 'androidx.navigation:navigation-ui:2.0.0-rc02'

View File

@ -2,23 +2,18 @@ package net.dankito.banking.fints4java.android
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.SubMenu
import android.widget.TextView
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat
import androidx.drawerlayout.widget.DrawerLayout
import com.github.clans.fab.FloatingActionMenu
import com.google.android.material.navigation.NavigationView
import kotlinx.android.synthetic.main.action_view_account_menu_item.view.*
import kotlinx.android.synthetic.main.activity_main.*
import net.dankito.banking.fints4java.android.ui.views.DrawerView
import net.dankito.banking.fints4java.android.ui.views.MainActivityFloatingActionMenuButton
import net.dankito.banking.fints4java.android.util.Base64ServiceAndroid
import net.dankito.banking.fints4javaBankingClientCreator
import net.dankito.banking.persistence.BankingPersistenceJson
import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.utils.web.client.OkHttpWebClient
import org.slf4j.LoggerFactory
@ -36,6 +31,8 @@ class MainActivity : AppCompatActivity() {
private lateinit var drawerToggle: ActionBarDrawerToggle
private lateinit var drawerView: DrawerView
private lateinit var floatingActionMenuButton: MainActivityFloatingActionMenuButton
@ -60,7 +57,6 @@ class MainActivity : AppCompatActivity() {
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navigationView: NavigationView = findViewById(R.id.nav_view)
// val navController = findNavController(R.id.nav_host_fragment)
// // Passing each menu ID as a set of Ids because each
@ -80,7 +76,9 @@ class MainActivity : AppCompatActivity() {
drawerLayout.addDrawerListener(drawerToggle)
drawerToggle.syncState()
setupNavigationView(navigationView, drawerLayout)
slider?.let { slider ->
drawerView = DrawerView(this, slider, presenter)
}
val floatingActionMenu = findViewById<FloatingActionMenu>(R.id.floatingActionMenu)
floatingActionMenuButton = MainActivityFloatingActionMenuButton(floatingActionMenu, presenter)
@ -93,89 +91,6 @@ class MainActivity : AppCompatActivity() {
}
private fun setupNavigationView(navigationView: NavigationView, drawerLayout: DrawerLayout) {
showAppVersion(navigationView)
val navigationMenu = navigationView.menu
val accountsMenuItem = navigationMenu.findItem(R.id.navBankAccountsSectionItem)
val accountsMenu = accountsMenuItem.subMenu
presenter.addAccountsChangedListener {
runOnUiThread { updateNavigationMenuItems(accountsMenu) }
}
updateNavigationMenuItems(accountsMenu)
navigationView.setNavigationItemSelectedListener { navigationItemSelected(it) }
}
private fun updateNavigationMenuItems(accountsMenu: SubMenu) {
accountsMenu.findItem(R.id.navAllBankAccounts).isVisible = presenter.accounts.isNotEmpty()
// removes previously shown accounts; index 0 = 'Add account', 1 = 'All accounts', don't remove these
for (index in (accountsMenu.size() - 1) downTo 2) {
accountsMenu.removeItem(accountsMenu.getItem(index).itemId)
}
presenter.accounts.forEach { account ->
val accountMenuItem = accountsMenu.add("")
accountMenuItem.setActionView(R.layout.action_view_account_menu_item)
accountMenuItem.actionView.txtvwAccountName.text = account.displayName
accountMenuItem.actionView.imgvwEditAccount.setImageResource(R.drawable.ic_build_white_48dp)
accountMenuItem.actionView.imgvwEditAccount.setOnClickListener { editAccount(account) }
accountMenuItem.setOnMenuItemClickListener { setSelectedAccount(account) }
}
}
private fun setSelectedAccount(account: Account): Boolean {
presenter.selectedAccount(account)
closeDrawer()
return true
}
private fun editAccount(account: Account) {
// TODO: implement
log.info("Edit account $account")
closeDrawer()
}
private fun showAppVersion(navigationView: NavigationView) {
try {
val packageInfo = this.packageManager.getPackageInfo(packageName, 0)
val version = packageInfo.versionName
(navigationView.getHeaderView(0).findViewById(R.id.txtAppVersion) as? TextView)?.text = version
} catch (e: Exception) {
log.error("Could not read application version")
}
}
private fun navigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.navAddBankAccount -> presenter.showAddAccountDialog()
R.id.navAllBankAccounts -> presenter.selectedAllBankAccounts()
}
closeDrawer()
return true
}
private fun closeDrawer() {
val drawer = findViewById(R.id.drawer_layout) as DrawerLayout
drawer.closeDrawer(GravityCompat.START)
}
// override fun onSupportNavigateUp(): Boolean {
// val navController = findNavController(R.id.nav_host_fragment)
// return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
// }
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
if(floatingActionMenuButton.handlesTouch(event)) { // close menu when menu is opened and touch is outside floatingActionMenuButton
return true

View File

@ -0,0 +1,19 @@
package net.dankito.banking.fints4java.android.ui.extensions
import android.content.Context
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.materialdrawer.iconics.withIcon
import com.mikepenz.materialdrawer.model.AbstractBadgeableDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.withIconColor
import net.dankito.utils.android.extensions.createColorStateList
fun <Item : AbstractBadgeableDrawerItem<Item>> AbstractBadgeableDrawerItem<Item>.withIcon(
context: Context, icon: IIcon, iconColorId: Int): AbstractBadgeableDrawerItem<Item> {
withIcon(icon)
withIconColor(context.createColorStateList(iconColorId))
return this
}

View File

@ -0,0 +1,148 @@
package net.dankito.banking.fints4java.android.ui.views
import android.view.View
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
import com.mikepenz.materialdrawer.model.SectionDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.*
import com.mikepenz.materialdrawer.util.addItems
import com.mikepenz.materialdrawer.util.addItemsAtPosition
import com.mikepenz.materialdrawer.util.removeItemByPosition
import com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.ui.extensions.withIcon
import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.presenter.BankingPresenter
import org.slf4j.LoggerFactory
open class DrawerView(
protected val activity: AppCompatActivity,
protected val slider: MaterialDrawerSliderView,
protected val presenter: BankingPresenter
) {
companion object {
private const val AccountLevel = 2
private const val BankAccountLevel = 7
private const val AccountsSectionHeaderId = 1000L
private const val AllAccountsId = 1001L
private const val AddAccountId = 1002L
private const val CountDefaultAccountItems = 3
private val log = LoggerFactory.getLogger(DrawerView::class.java)
}
init {
setupDrawerView()
}
protected open fun setupDrawerView() {
slider.headerView = activity.layoutInflater.inflate(R.layout.nav_header_main, null)
showAppVersion(slider.headerView)
setDefaultDrawerItems()
presenter.addAccountsChangedListener {
activity.runOnUiThread { updateDrawerItems() }
}
updateDrawerItems()
}
private fun setDefaultDrawerItems() {
slider.apply {
addItems(
SectionDrawerItem()
.withName(R.string.drawer_menu_bank_accounts_section_title)
.withIdentifier(AccountsSectionHeaderId)
.withDivider(false)
,
PrimaryDrawerItem()
.withName(R.string.drawer_menu_all_bank_accounts_title)
.withIdentifier(AllAccountsId)
.withLevel(AccountLevel)
.withSelected(true)
.withIcon(activity, GoogleMaterial.Icon.gmd_account_balance, R.color.primaryTextColor_Dark)
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAllBankAccounts() } }
,
PrimaryDrawerItem()
.withName(R.string.drawer_menu_add_bank_account_title)
.withIdentifier(AddAccountId)
.withLevel(AccountLevel)
.withIcon(activity, GoogleMaterial.Icon.gmd_add, R.color.primaryTextColor_Dark)
.withSelectable(false)
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.showAddAccountDialog() } }
)
}
}
private fun updateDrawerItems() {
// removes previously shown accounts; index 1 = 'Accounts header', 1 = 'All accounts', index 2 = 'Add account', don't remove these
while (slider.itemAdapter.adapterItems.size > CountDefaultAccountItems) {
slider.removeItemByPosition(CountDefaultAccountItems)
}
val accountItems = createAccountsDrawerItems()
slider.addItemsAtPosition(CountDefaultAccountItems, *accountItems.toTypedArray())
}
private fun createAccountsDrawerItems(): List<IDrawerItem<*>> {
return presenter.accounts.map { account ->
val accountItem = createAccountDrawerItem(account)
val bankAccountsItems = createBankAccountsDrawerItems(account).toMutableList()
bankAccountsItems.add(0, accountItem)
return@map bankAccountsItems
}.flatten()
}
private fun createAccountDrawerItem(account: Account): PrimaryDrawerItem {
return PrimaryDrawerItem()
.withName(account.displayName)
.withLevel(AccountLevel)
.withIcon(activity, FontAwesome.Icon.faw_piggy_bank, R.color.primaryTextColor_Dark)
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAccount(account) } }
}
private fun createBankAccountsDrawerItems(account: Account): List<IDrawerItem<*>> {
return account.bankAccounts.map { bankAccount ->
SecondaryDrawerItem()
.withName(bankAccount.displayName)
.withLevel(BankAccountLevel)
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedBankAccount(bankAccount) } }
}
}
private fun itemClicked(action: () -> Unit): Boolean {
action()
return false
}
private fun showAppVersion(navigationHeaderView: View?) {
try {
val packageInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
val version = packageInfo.versionName
(navigationHeaderView?.findViewById(R.id.txtAppVersion) as? TextView)?.text = version
} catch (e: Exception) {
log.error("Could not read application version")
}
}
}

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="@+id/txtvwAccountName"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/imgvwEditAccount"
android:layout_toStartOf="@+id/imgvwEditAccount"
android:gravity="center_vertical"
android:textColor="@color/primaryTextColor_Dark"
/>
<ImageView
android:id="@+id/imgvwEditAccount"
android:layout_width="@dimen/navigation_menu_icon_edit_account_width_and_height"
android:layout_height="@dimen/navigation_menu_icon_edit_account_width_and_height"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="@dimen/navigation_menu_icon_and_space_width"
android:layout_marginEnd="@dimen/navigation_menu_icon_and_space_width"
android:src="@drawable/ic_check_circle_white_48dp"
/>
</RelativeLayout>

View File

@ -15,16 +15,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer"
android:theme="@style/AppTheme.NavigationView"
android:background="@color/backgroundColor_Dark"
/>
<com.mikepenz.materialdrawer.widget.MaterialDrawerSliderView
android:id="@+id/slider"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="false"
/>
</androidx.drawerlayout.widget.DrawerLayout>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:showIn="navigation_view"
>
<item
android:id="@+id/navBankAccountsSectionItem"
android:title="@string/nav_menu_bank_accounts_section_title"
>
<menu
android:id="@+id/navBankAccountsSectionMenu"
>
<item
android:id="@+id/navAddBankAccount"
android:icon="@drawable/ic_add_white_48dp"
android:title="@string/nav_menu_add_bank_account_title"
/>
<item
android:id="@+id/navAllBankAccounts"
android:title="@string/nav_menu_all_bank_accounts_title"
android:visible="false"
/>
</menu>
</item>
</menu>

View File

@ -15,9 +15,9 @@
<string name="nav_header_title">@string/app_name</string>
<string name="nav_header_version_label">Version\u0020</string>
<string name="nav_header_desc">Navigationsbereich</string>
<string name="nav_menu_bank_accounts_section_title">Konten</string>
<string name="nav_menu_add_bank_account_title">Konto hinzufügen</string>
<string name="nav_menu_all_bank_accounts_title">Alle Konten</string>
<string name="drawer_menu_bank_accounts_section_title">Konten</string>
<string name="drawer_menu_add_bank_account_title">Konto hinzufügen</string>
<string name="drawer_menu_all_bank_accounts_title">Alle Konten</string>
<string name="floating_action_menu_add_account">Konto</string>
<string name="floating_action_menu_transfer_money">Überweisung</string>

View File

@ -4,9 +4,6 @@
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</dimen>
<dimen name="navigation_menu_icon_title_space">8dp</dimen>
<dimen name="navigation_menu_icon_and_space_width">56dp</dimen>
<dimen name="navigation_menu_icon_edit_account_width_and_height">24dp</dimen>
<dimen name="fab_margin">16dp</dimen>
<dimen name="fab_margin_bottom_without_toolbar">16dp</dimen>
<dimen name="fab_margin_bottom_with_toolbar">42dp</dimen>

View File

@ -1,3 +0,0 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
</resources>

View File

@ -15,9 +15,9 @@
<string name="nav_header_title">@string/app_name</string>
<string name="nav_header_version_label">Version\u0020</string>
<string name="nav_header_desc">Navigation header</string>
<string name="nav_menu_bank_accounts_section_title">Accounts</string>
<string name="nav_menu_add_bank_account_title">Add account</string>
<string name="nav_menu_all_bank_accounts_title">All accounts</string>
<string name="drawer_menu_bank_accounts_section_title">Accounts</string>
<string name="drawer_menu_all_bank_accounts_title">All accounts</string>
<string name="drawer_menu_add_bank_account_title">Add account</string>
<string name="floating_action_menu_add_account">Account</string>
<string name="floating_action_menu_transfer_money">Transfer money</string>

View File

@ -10,6 +10,18 @@
<item name="fabTextColor">@color/fabTextColor</item>
<item name="fabLabelBackgroundColor">@color/fabLabelBackgroundColor</item>
<item name="fabShadowColor">@color/fabShadowColor</item>
<!-- for MaterialDrawer-->
<item name="materialDrawerStyle">@style/Widget.MaterialDrawerStyleCustom</item>
<item name="materialDrawerHeaderStyle">@style/Widget.MaterialDrawerHeaderStyle</item>
</style>
<style name="Widget.MaterialDrawerStyleCustom" parent="Widget.MaterialDrawerStyle">
<item name="materialDrawerBackground">@color/backgroundColor_Dark</item>
<item name="materialDrawerPrimaryText">@color/primaryTextColor_Dark</item>
<item name="materialDrawerSecondaryText">@color/primaryTextColor_Dark</item>
<item name="materialDrawerDividerColor">@color/primaryTextColor_Dark</item>
<item name="materialDrawerSelectedBackgroundColor">@color/colorAccent</item>
</style>
<style name="AppTheme.NoActionBar">
@ -21,15 +33,6 @@
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="AppTheme.NavigationView">
<!-- Sets group title's text color -->
<item name="android:textColorSecondary">@color/primaryTextColor_Dark</item>
<!-- Sets menu items' text color -->
<item name="itemTextColor">@color/primaryTextColor_Dark</item>
<item name="itemIconTint">@color/primaryTextColor_Dark</item>
<item name="itemIconPadding">@dimen/navigation_menu_icon_title_space</item>
</style>
<!-- TODO: simply use Dialog as soon as AndroidUtils 2.0.0 is out -->
<style name="FloatingDialog" parent="Dialog">
<!-- to prevent that keyboard covers dialog -->