Added FloatingActionMenuButton so that users can trigger a money transfer without having to long click on an account transaction

This commit is contained in:
dankl 2020-01-03 17:57:05 +01:00 committed by dankito
parent 941746c18b
commit 87985469bf
15 changed files with 304 additions and 15 deletions

View File

@ -7,10 +7,12 @@ ext {
kotlinVersion = '1.3.41'
javaUtilsVersion = '1.0.8'
javaUtilsVersion = '1.0.9'
androidUtilsVersion = '1.1.0'
clansFloatingActionButtonVersion = '1.6.4'
javaFxUtilsVersion = '1.0.3'
junitVersion = '4.12'

View File

@ -53,6 +53,8 @@ dependencies {
// TODO: try to get rid of this import
implementation project(':fints4javaLib')
implementation "com.github.clans:fab:$clansFloatingActionButtonVersion"
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
api "net.dankito.utils:android-utils:$androidUtilsVersion", {

View File

@ -1,18 +1,19 @@
package net.dankito.banking.fints4java.android
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.design.widget.NavigationView
import android.support.v4.widget.DrawerLayout
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
import androidx.navigation.findNavController
import com.github.clans.fab.FloatingActionMenu
import kotlinx.android.synthetic.main.action_view_account_menu_item.view.*
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.fints4java.android.ui.dialogs.AddAccountDialog
import net.dankito.banking.fints4java.android.ui.dialogs.EnterAtcDialog
import net.dankito.banking.fints4java.android.ui.dialogs.EnterTanDialog
import net.dankito.banking.mapper.fints4javaModelMapper
import net.dankito.banking.fints4java.android.ui.views.MainActivityFloatingActionMenuButton
import net.dankito.banking.ui.BankingClientCallback
import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
@ -27,6 +28,9 @@ class MainActivity : AppCompatActivity() {
// private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var floatingActionMenuButton: MainActivityFloatingActionMenuButton
val presenter = MainWindowPresenter(Base64ServiceAndroid(), object : BankingClientCallback {
override fun enterTan(account: Account, tanChallenge: TanChallenge): EnterTanResult {
@ -52,11 +56,6 @@ class MainActivity : AppCompatActivity() {
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val fab: FloatingActionButton = findViewById(R.id.fab)
fab.setOnClickListener { view ->
AddAccountDialog().show(this, presenter)
}
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
@ -71,11 +70,13 @@ class MainActivity : AppCompatActivity() {
// )
//
// setupActionBarWithNavController(navController, appBarConfiguration)
// navView.setupWithNavController(navController)
// navigationView.setupWithNavController(navController)
val floatingActionMenu = findViewById<FloatingActionMenu>(R.id.floatingActionMenu)
floatingActionMenuButton = MainActivityFloatingActionMenuButton(floatingActionMenu, presenter)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
@ -86,6 +87,24 @@ class MainActivity : AppCompatActivity() {
// 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
}
return super.dispatchTouchEvent(event)
}
override fun onBackPressed() {
if (floatingActionMenuButton.handlesBackButtonPress()) { // close menu when menu is opened and back button gets pressed
return
}
super.onBackPressed()
}
private fun getTanFromUserOffUiThread(account: Account, tanChallenge: TanChallenge): EnterTanResult {
val enteredTan = AtomicReference<EnterTanResult>(null)
val tanEnteredLatch = CountDownLatch(1)
@ -107,7 +126,6 @@ class MainActivity : AppCompatActivity() {
val tanEnteredLatch = CountDownLatch(1)
runOnUiThread {
// TODO: don't create a fints4javaModelMapper instance here, let MainWindowPresenter do the job
EnterAtcDialog().show(tanMedium, this@MainActivity, false) { enteredResult ->
result.set(enteredResult)
tanEnteredLatch.countDown()

View File

@ -0,0 +1,78 @@
package net.dankito.banking.fints4java.android.ui.views
import android.os.Bundle
import android.view.MotionEvent
import com.github.clans.fab.FloatingActionMenu
import net.dankito.utils.android.extensions.isTouchInsideView
open class FloatingActionMenuButton(protected val floatingActionMenu: FloatingActionMenu) {
companion object {
private const val IS_OPENED_EXTRA_NAME = "IS_OPENED"
}
private var isClosingMenu = false
init {
setup()
}
protected open fun setup() {
floatingActionMenu.setClosedOnTouchOutside(true)
floatingActionMenu.setOnMenuToggleListener { isClosingMenu = false }
}
protected open fun executeAndCloseMenu(action: () -> Unit) {
action() // first execute action and then close menu as when action sets menu items visibility closeMenu() would otherwise overwrite this value
closeMenu()
}
protected open fun closeMenu() {
isClosingMenu = true // as closing is animated it takes till animation end till floatingActionMenu.isOpened is set to true
floatingActionMenu.close(true)
}
open fun handlesBackButtonPress(): Boolean {
if(floatingActionMenu.isOpened) {
closeMenu()
return true
}
return false
}
open fun handlesTouch(event: MotionEvent): Boolean {
if(floatingActionMenu.isOpened) { // if menu is opened and user clicked somewhere else in the view, close menu
if(floatingActionMenu.isTouchInsideView(event) == false) {
closeMenu()
return true
}
}
return false
}
open fun saveInstanceState(outState: Bundle?) {
outState?.let {
outState.putBoolean(IS_OPENED_EXTRA_NAME, floatingActionMenu.isOpened && isClosingMenu == false)
}
}
open fun restoreInstanceState(savedInstanceState: Bundle?) {
savedInstanceState?.let {
if(savedInstanceState.getBoolean(IS_OPENED_EXTRA_NAME, false)) {
floatingActionMenu.open(false)
}
}
}
}

View File

@ -0,0 +1,39 @@
package net.dankito.banking.fints4java.android.ui.views
import android.support.v7.app.AppCompatActivity
import com.github.clans.fab.FloatingActionMenu
import kotlinx.android.synthetic.main.view_floating_action_button_main.view.*
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
import net.dankito.banking.fints4java.android.ui.dialogs.AddAccountDialog
import net.dankito.banking.fints4java.android.ui.dialogs.TransferMoneyDialog
open class MainActivityFloatingActionMenuButton(floatingActionMenu: FloatingActionMenu, protected val presenter: MainWindowPresenter)
: FloatingActionMenuButton(floatingActionMenu) {
init {
setupButtons(floatingActionMenu)
}
private fun setupButtons(floatingActionMenu: FloatingActionMenu) {
(floatingActionMenu.context as? AppCompatActivity)?.let { activity ->
floatingActionMenu.fabAddAccount.setOnClickListener {
executeAndCloseMenu { AddAccountDialog().show(activity, presenter) }
}
val fabTransferMoney = floatingActionMenu.fabTransferMoney
fabTransferMoney.isEnabled = false
floatingActionMenu.setOnMenuToggleListener {
if (floatingActionMenu.isOpened) {
fabTransferMoney.isEnabled = presenter.accounts.isNotEmpty()
}
}
fabTransferMoney.setOnClickListener {
executeAndCloseMenu { TransferMoneyDialog().show(activity, presenter, null) }
}
}
}
}

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:interpolator/overshoot">
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:duration="400" />
<translate
android:fromYDelta="30%p"
android:toYDelta="0"
android:duration="300" />
</set>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/anticipate_interpolator">
<alpha
android:fromAlpha="1"
android:toAlpha="0"
android:duration="200" />
<translate
android:fromYDelta="0"
android:toYDelta="30%p"
android:duration="200" />
</set>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?attr/fabLabelBackgroundColor"/>
<padding
android:left="16dp"
android:top="4dp"
android:right="16dp"
android:bottom="4dp"/>
<corners
android:radius="2dp"/>
</shape>

View File

@ -22,12 +22,15 @@
<include layout="@layout/content_main" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
<include
layout="@layout/view_floating_action_button_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
app:srcCompat="@drawable/ic_add_white_48dp" />
android:layout_marginRight="@dimen/fab_margin"
android:layout_marginEnd="@dimen/fab_margin"
android:layout_marginBottom="@dimen/fab_margin_bottom_without_toolbar"
app:layout_behavior="@string/move_upward_behaviour"
/>
</android.support.design.widget.CoordinatorLayout>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<com.github.clans.fab.FloatingActionMenu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:id="@+id/floatingActionMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
fab:menu_labels_style="@style/MenuLabelsStyle"
fab:menu_shadowColor="#444"
fab:menu_colorNormal="?attr/colorAccent"
fab:menu_colorPressed="?attr/colorPrimary"
fab:menu_colorRipple="?attr/colorPrimaryDark"
fab:menu_animationDelayPerItem="50">
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fabTransferMoney"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MenuButtonsStyle"
fab:fab_label="@string/floating_action_menu_transfer_money"
/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fabAddAccount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/MenuButtonsStyle"
fab:fab_label="@string/floating_action_menu_add_account"
/>
</com.github.clans.fab.FloatingActionMenu>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Theme">
<attr name="fabTextColor" format="reference"/>
<attr name="fabLabelBackgroundColor" format="reference"/>
<attr name="fabShadowColor" format="reference"/>
</declare-styleable>
</resources>

View File

@ -1,6 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="primaryTextColor_Dark">#BABABA</color>
<color name="primaryTextColor_Light">#000000</color>
<color name="backgroundColor_Dark">#303030</color>
<color name="backgroundColor_Light">#FFFFFF</color>
<color name="positiveAmount">#00FF00</color>
<color name="negativeAmount">#FF0000</color>
@ -9,4 +15,10 @@
<color name="list_item_bank_info_bank_supported">#ff669900</color>
<color name="list_item_bank_info_bank_not_supported">#ffcc0000</color>
<color name="fabTextColor">#FFFFFF</color>
<!-- <color name="fabLabelBackgroundColor">@color/black_semi_transparent</color>-->
<color name="fabLabelBackgroundColor">@color/colorAccent</color>
<color name="fabShadowColor">#444</color>
</resources>

View File

@ -5,6 +5,8 @@
<dimen name="nav_header_vertical_spacing">8dp</dimen>
<dimen name="nav_header_height">176dp</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>
<dimen name="list_item_account_transaction_height">100dp</dimen>
<dimen name="list_item_account_transaction_padding">4dp</dimen>

View File

@ -17,6 +17,9 @@
<string name="nav_header_subtitle">android.studio@android.com</string>
<string name="nav_header_desc">Navigation header</string>
<string name="floating_action_menu_add_account">Account</string>
<string name="floating_action_menu_transfer_money">Transfer money</string>
<string name="menu_home">Home</string>
<string name="menu_main_update_transactions">Update transactions</string>

View File

@ -6,6 +6,10 @@
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="fabTextColor">@color/fabTextColor</item>
<item name="fabLabelBackgroundColor">@color/fabLabelBackgroundColor</item>
<item name="fabShadowColor">@color/fabShadowColor</item>
</style>
<style name="AppTheme.NoActionBar">
@ -17,4 +21,40 @@
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<!-- Floating Action Button -->
<style name="MenuLabelsStyle">
<item name="android:background">@drawable/fab_label_background</item>
<item name="android:textColor">?attr/fabTextColor</item>
<item name="android:textSize">14sp</item>
<item name="android:maxLines">2</item>
<item name="android:ellipsize">end</item>
<item name="android:gravity">center_vertical</item>
<item name="menu_shadowColor">?attr/fabShadowColor</item>
<item name="menu_colorNormal">?attr/colorPrimary</item>
<item name="menu_colorPressed">?attr/colorAccent</item>
<item name="menu_colorRipple">?attr/colorPrimaryDark</item>
<item name="fab_showAnimation">@anim/jump_from_down</item>
<item name="fab_hideAnimation">@anim/jump_to_down</item>
</style>
<style name="MenuButtonsStyle">
<item name="android:textColor">?attr/fabTextColor</item>
<item name="fab_size">mini</item>
<item name="fab_shadowColor">?attr/fabShadowColor</item>
<item name="fab_colorNormal">?attr/colorAccent</item>
<item name="fab_colorPressed">?attr/colorPrimary</item>
<item name="fab_colorRipple">?attr/colorPrimaryDark</item>
<item name="fab_showAnimation">@anim/jump_from_down</item>
<item name="fab_hideAnimation">@anim/jump_to_down</item>
<item name="android:src">@drawable/fab_add</item>
</style>
</resources>