Implemented deleting an account (TODO: implement dialog to edit account e.g. set display name etc.)
|
@ -7,6 +7,8 @@ interface IBankingPersistence {
|
||||||
|
|
||||||
fun saveOrUpdateAccount(account: Account, allAccounts: List<Account>)
|
fun saveOrUpdateAccount(account: Account, allAccounts: List<Account>)
|
||||||
|
|
||||||
|
fun deleteAccount(account: Account, allAccounts: List<Account>)
|
||||||
|
|
||||||
fun readPersistedAccounts(): List<Account>
|
fun readPersistedAccounts(): List<Account>
|
||||||
|
|
||||||
}
|
}
|
|
@ -158,6 +158,21 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun deleteAccount(account: Account) {
|
||||||
|
val wasSelected = isSingleSelectedAccount(account) or // either account or one of its bank accounts is currently selected
|
||||||
|
(account.bankAccounts.firstOrNull { isSingleSelectedBankAccount(it) } != null)
|
||||||
|
|
||||||
|
clientsForAccounts.remove(account)
|
||||||
|
|
||||||
|
persister.deleteAccount(account, accounts)
|
||||||
|
|
||||||
|
callAccountsChangedListeners()
|
||||||
|
|
||||||
|
if (wasSelected) {
|
||||||
|
selectedAllBankAccounts()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun getAccountTransactionsAsync(account: Account,
|
open fun getAccountTransactionsAsync(account: Account,
|
||||||
callback: (GetTransactionsResponse) -> Unit) {
|
callback: (GetTransactionsResponse) -> Unit) {
|
||||||
|
|
|
@ -3,13 +3,14 @@ package net.dankito.banking.fints4java.android.ui.extensions
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.mikepenz.iconics.typeface.IIcon
|
import com.mikepenz.iconics.typeface.IIcon
|
||||||
import com.mikepenz.materialdrawer.iconics.withIcon
|
import com.mikepenz.materialdrawer.iconics.withIcon
|
||||||
import com.mikepenz.materialdrawer.model.AbstractBadgeableDrawerItem
|
import com.mikepenz.materialdrawer.model.BaseDescribeableDrawerItem
|
||||||
|
import com.mikepenz.materialdrawer.model.BaseViewHolder
|
||||||
import com.mikepenz.materialdrawer.model.interfaces.withIconColor
|
import com.mikepenz.materialdrawer.model.interfaces.withIconColor
|
||||||
import net.dankito.utils.android.extensions.createColorStateList
|
import net.dankito.utils.android.extensions.createColorStateList
|
||||||
|
|
||||||
|
|
||||||
fun <Item : AbstractBadgeableDrawerItem<Item>> AbstractBadgeableDrawerItem<Item>.withIcon(
|
fun <T, VH : BaseViewHolder> BaseDescribeableDrawerItem<T, VH>.withIcon(context: Context, icon: IIcon, iconColorId: Int)
|
||||||
context: Context, icon: IIcon, iconColorId: Int): AbstractBadgeableDrawerItem<Item> {
|
: BaseDescribeableDrawerItem<T, VH> {
|
||||||
|
|
||||||
withIcon(icon)
|
withIcon(icon)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package net.dankito.banking.fints4java.android.ui.views
|
||||||
|
|
||||||
|
|
||||||
|
class AccountDrawerItem : SecondaryIconDrawerItem<AccountDrawerItem>() {
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,10 @@ package net.dankito.banking.fints4java.android.ui.views
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import androidx.core.view.GravityCompat
|
||||||
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome
|
import com.mikepenz.iconics.typeface.library.fontawesome.FontAwesome
|
||||||
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
|
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
|
||||||
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
|
||||||
|
@ -112,10 +115,15 @@ open class DrawerView(
|
||||||
}.flatten()
|
}.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createAccountDrawerItem(account: Account): PrimaryDrawerItem {
|
private fun createAccountDrawerItem(account: Account): IDrawerItem<*> {
|
||||||
return PrimaryDrawerItem()
|
|
||||||
|
return AccountDrawerItem()
|
||||||
.withName(account.displayName)
|
.withName(account.displayName)
|
||||||
.withLevel(AccountLevel)
|
.withLevel(AccountLevel)
|
||||||
|
// .withSecondaryIcon(GoogleMaterial.Icon.gmd_settings) // used when editing account is implemented
|
||||||
|
.withSecondaryIcon(GoogleMaterial.Icon.gmd_delete)
|
||||||
|
.withSecondaryIconColor(activity, R.color.primaryTextColor_Dark)
|
||||||
|
.withOnSecondaryIconClickedListener { closeDrawerAndEditAccount(account) }
|
||||||
.withIcon(activity, FontAwesome.Icon.faw_piggy_bank, R.color.primaryTextColor_Dark)
|
.withIcon(activity, FontAwesome.Icon.faw_piggy_bank, R.color.primaryTextColor_Dark)
|
||||||
.withSelected(presenter.isSingleSelectedAccount(account))
|
.withSelected(presenter.isSingleSelectedAccount(account))
|
||||||
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAccount(account) } }
|
.withOnDrawerItemClickListener { _, _, _ -> itemClicked { presenter.selectedAccount(account) } }
|
||||||
|
@ -137,6 +145,25 @@ open class DrawerView(
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun closeDrawerAndEditAccount(account: Account) {
|
||||||
|
closeDrawer()
|
||||||
|
|
||||||
|
editAccount(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun editAccount(account: Account) {
|
||||||
|
// TODO: implement editing account (e.g. displayed name etc.)
|
||||||
|
|
||||||
|
AlertDialog.Builder(activity)
|
||||||
|
.setMessage(activity.getString(R.string.dialog_edit_account_ask_should_account_be_deleted, account.displayName))
|
||||||
|
.setPositiveButton(R.string.delete) { dialog, _ ->
|
||||||
|
dialog.dismiss()
|
||||||
|
presenter.deleteAccount(account)
|
||||||
|
}
|
||||||
|
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun showAppVersion(navigationHeaderView: View?) {
|
private fun showAppVersion(navigationHeaderView: View?) {
|
||||||
try {
|
try {
|
||||||
val packageInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
|
val packageInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
|
||||||
|
@ -147,4 +174,9 @@ open class DrawerView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun closeDrawer() {
|
||||||
|
val drawerLayout = activity.findViewById<DrawerLayout>(R.id.drawer_layout)
|
||||||
|
drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
package net.dankito.banking.fints4java.android.ui.views
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.LayoutRes
|
||||||
|
import com.mikepenz.iconics.typeface.IIcon
|
||||||
|
import com.mikepenz.materialdrawer.holder.ImageHolder
|
||||||
|
import com.mikepenz.materialdrawer.iconics.IconicsImageHolder
|
||||||
|
import com.mikepenz.materialdrawer.model.BaseDescribeableDrawerItem
|
||||||
|
import com.mikepenz.materialdrawer.model.BaseViewHolder
|
||||||
|
import net.dankito.banking.fints4java.android.R
|
||||||
|
import net.dankito.utils.android.extensions.createColorStateList
|
||||||
|
|
||||||
|
|
||||||
|
open class SecondaryIconDrawerItem<Item : SecondaryIconDrawerItem<Item>> : BaseDescribeableDrawerItem<Item, SecondaryIconDrawerItem.ViewHolder>() {
|
||||||
|
|
||||||
|
var secondaryIcon: ImageHolder? = null
|
||||||
|
|
||||||
|
var secondaryIconColor: ColorStateList? = null
|
||||||
|
|
||||||
|
var onSecondaryIconClicked: (() -> Unit)? = null
|
||||||
|
|
||||||
|
|
||||||
|
override val type: Int
|
||||||
|
get() = R.id.material_drawer_item_secondary_icon
|
||||||
|
|
||||||
|
override val layoutRes: Int
|
||||||
|
@LayoutRes
|
||||||
|
get() = R.layout.material_drawer_item_secondary_icon
|
||||||
|
|
||||||
|
|
||||||
|
override fun bindView(holder: ViewHolder, payloads: List<Any>) {
|
||||||
|
super.bindView(holder, payloads)
|
||||||
|
|
||||||
|
bindViewHelper(holder)
|
||||||
|
|
||||||
|
if (secondaryIcon == null) {
|
||||||
|
holder.btnSecondaryIcon.visibility = View.GONE
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val context = holder.itemView.context
|
||||||
|
val secondaryIconColor = this.secondaryIconColor ?: getIconColor(context)
|
||||||
|
val secondaryIcon = ImageHolder.decideIcon(secondaryIcon, context, secondaryIconColor, isIconTinted, 1)
|
||||||
|
|
||||||
|
holder.btnSecondaryIcon.setImageDrawable(secondaryIcon)
|
||||||
|
|
||||||
|
holder.btnSecondaryIcon.setOnClickListener { onSecondaryIconClicked?.invoke() }
|
||||||
|
|
||||||
|
holder.btnSecondaryIcon.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
//call the onPostBindView method to trigger post bind view actions (like the listener to modify the item if required)
|
||||||
|
onPostBindView(this, holder.itemView)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getViewHolder(v: View): ViewHolder {
|
||||||
|
return ViewHolder(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ViewHolder(view: View) : BaseViewHolder(view) {
|
||||||
|
internal val btnSecondaryIcon = view.findViewById<ImageView>(R.id.btnSecondaryIcon)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun withSecondaryIconColor(iconColor: ColorStateList): Item {
|
||||||
|
this.secondaryIconColor = iconColor
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun withSecondaryIconColor(context: Context, iconColorResId: Int): Item {
|
||||||
|
return withSecondaryIconColor(context.createColorStateList(iconColorResId))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun withSecondaryIcon(icon: Drawable?): Item {
|
||||||
|
this.secondaryIcon = ImageHolder(icon)
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun withSecondaryIcon(icon: Bitmap): Item {
|
||||||
|
this.secondaryIcon = ImageHolder(icon)
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun withSecondaryIcon(@DrawableRes imageRes: Int): Item {
|
||||||
|
this.secondaryIcon = ImageHolder(imageRes)
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun withSecondaryIcon(url: String): Item {
|
||||||
|
this.secondaryIcon = ImageHolder(url)
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun withSecondaryIcon(uri: Uri): Item {
|
||||||
|
this.secondaryIcon = ImageHolder(uri)
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun withSecondaryIcon(icon: ImageHolder?): Item {
|
||||||
|
this.secondaryIcon = icon
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun withSecondaryIcon(icon: IIcon): Item {
|
||||||
|
this.secondaryIcon = IconicsImageHolder(icon)
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun withOnSecondaryIconClickedListener(clickListener: () -> Unit): Item {
|
||||||
|
this.onSecondaryIconClicked = clickListener
|
||||||
|
return this as Item
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Before Width: | Height: | Size: 97 B |
Before Width: | Height: | Size: 547 B |
Before Width: | Height: | Size: 726 B |
Before Width: | Height: | Size: 97 B |
Before Width: | Height: | Size: 344 B |
Before Width: | Height: | Size: 469 B |
Before Width: | Height: | Size: 102 B |
Before Width: | Height: | Size: 655 B |
Before Width: | Height: | Size: 931 B |
Before Width: | Height: | Size: 113 B |
Before Width: | Height: | Size: 980 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 116 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/material_drawer_item_primary"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingEnd="@dimen/material_drawer_vertical_padding"
|
||||||
|
android:paddingLeft="@dimen/material_drawer_vertical_padding"
|
||||||
|
android:paddingRight="@dimen/material_drawer_vertical_padding"
|
||||||
|
android:paddingStart="@dimen/material_drawer_vertical_padding">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/material_drawer_icon"
|
||||||
|
android:layout_width="@dimen/material_drawer_item_primary_icon"
|
||||||
|
android:layout_height="@dimen/material_drawer_item_primary"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:paddingBottom="@dimen/material_drawer_item_primary_icon_padding"
|
||||||
|
android:paddingEnd="@dimen/material_drawer_item_primary_icon_padding_right"
|
||||||
|
android:paddingLeft="0dp"
|
||||||
|
android:paddingRight="@dimen/material_drawer_item_primary_icon_padding_right"
|
||||||
|
android:paddingStart="0dp"
|
||||||
|
android:paddingTop="@dimen/material_drawer_item_primary_icon_padding" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:gravity="center_vertical|start"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/material_drawer_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:gravity="center_vertical|start"
|
||||||
|
android:lines="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textDirection="anyRtl"
|
||||||
|
android:textSize="@dimen/material_drawer_item_primary_text"
|
||||||
|
tools:text="Some drawer text" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/material_drawer_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif"
|
||||||
|
android:gravity="center_vertical|start"
|
||||||
|
android:lines="1"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textDirection="anyRtl"
|
||||||
|
android:textSize="@dimen/material_drawer_item_primary_description"
|
||||||
|
tools:text="Some drawer text" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btnSecondaryIcon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:paddingLeft="@dimen/material_drawer_vertical_padding"
|
||||||
|
android:paddingRight="0dp"
|
||||||
|
android:paddingStart="@dimen/material_drawer_vertical_padding"
|
||||||
|
android:scaleType="fitCenter" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -7,6 +7,7 @@
|
||||||
<string name="yes">Ja</string>
|
<string name="yes">Ja</string>
|
||||||
<string name="no">Nein</string>
|
<string name="no">Nein</string>
|
||||||
<string name="fetch">Abrufen</string>
|
<string name="fetch">Abrufen</string>
|
||||||
|
<string name="delete">Löschen</string>
|
||||||
|
|
||||||
<string name="search">Suchen</string>
|
<string name="search">Suchen</string>
|
||||||
|
|
||||||
|
@ -84,4 +85,7 @@
|
||||||
<string name="dialog_enter_atc_atc_label">ATC:</string>
|
<string name="dialog_enter_atc_atc_label">ATC:</string>
|
||||||
<string name="dialog_enter_atc_error_entered_atc_is_not_a_number">ATC muss eine Zahl sein.\n\nDer eingebene ATC Wert \'%s\' kann jedoch nicht in eine Zahl konvertiert werden.</string>
|
<string name="dialog_enter_atc_error_entered_atc_is_not_a_number">ATC muss eine Zahl sein.\n\nDer eingebene ATC Wert \'%s\' kann jedoch nicht in eine Zahl konvertiert werden.</string>
|
||||||
|
|
||||||
|
<string name="dialog_edit_account_ask_should_account_be_deleted">Möchten Sie das Konto \'%s\' wirklich löschen?
|
||||||
|
\n\nDies kann nicht rückgängig gemacht werden und die hierzu gespeicherten Daten gehen unwiederbringlich verloren.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
<color name="backgroundColor_Dark">#303030</color>
|
<color name="backgroundColor_Dark">#303030</color>
|
||||||
<color name="backgroundColor_Light">#FFFFFF</color>
|
<color name="backgroundColor_Light">#FFFFFF</color>
|
||||||
|
|
||||||
|
<color name="drawerMenuItemPrimaryColor">@color/primaryTextColor_Dark</color>
|
||||||
|
|
||||||
<color name="positiveAmount">#43A047</color>
|
<color name="positiveAmount">#43A047</color>
|
||||||
<color name="negativeAmount">#E53935</color>
|
<color name="negativeAmount">#E53935</color>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<item name="material_drawer_item_secondary_icon" type="id" />
|
||||||
|
|
||||||
|
</resources>
|
|
@ -7,6 +7,7 @@
|
||||||
<string name="yes">Yes</string>
|
<string name="yes">Yes</string>
|
||||||
<string name="no">No</string>
|
<string name="no">No</string>
|
||||||
<string name="fetch">Fetch</string>
|
<string name="fetch">Fetch</string>
|
||||||
|
<string name="delete">Delete</string>
|
||||||
|
|
||||||
<string name="search">Search</string>
|
<string name="search">Search</string>
|
||||||
|
|
||||||
|
@ -84,4 +85,7 @@
|
||||||
<string name="dialog_enter_atc_atc_label">ATC:</string>
|
<string name="dialog_enter_atc_atc_label">ATC:</string>
|
||||||
<string name="dialog_enter_atc_error_entered_atc_is_not_a_number">ATC has to be a number.\n\nBut entered ATC value \'%s\' cannot be converted to a number.</string>
|
<string name="dialog_enter_atc_error_entered_atc_is_not_a_number">ATC has to be a number.\n\nBut entered ATC value \'%s\' cannot be converted to a number.</string>
|
||||||
|
|
||||||
|
<string name="dialog_edit_account_ask_should_account_be_deleted">Really delete account \'%s\'?
|
||||||
|
\n\nThis cannot be undone and data will be lost.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -21,6 +21,10 @@ open class BankingPersistenceJson(
|
||||||
serializer.serializeObject(allAccounts, jsonFile)
|
serializer.serializeObject(allAccounts, jsonFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun deleteAccount(account: Account, allAccounts: List<Account>) {
|
||||||
|
serializer.serializeObject(allAccounts, jsonFile)
|
||||||
|
}
|
||||||
|
|
||||||
override fun readPersistedAccounts(): List<Account> {
|
override fun readPersistedAccounts(): List<Account> {
|
||||||
return serializer.deserializeListOr(jsonFile, Account::class.java, listOf())
|
return serializer.deserializeListOr(jsonFile, Account::class.java, listOf())
|
||||||
}
|
}
|
||||||
|
|