Using now Dagger to inject dependencies (fixes that on resume Dialogs don't crash)

This commit is contained in:
dankito 2020-04-23 20:35:25 +02:00
parent a8ae3e9006
commit d6b136e7f3
10 changed files with 207 additions and 38 deletions

View File

@ -31,6 +31,8 @@ ext {
materialComponentsVersion = "1.1.0" materialComponentsVersion = "1.1.0"
daggerVersion = "2.27"
/* JavaFX */ /* JavaFX */

View File

@ -1,6 +1,8 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android { android {
compileSdkVersion 28 compileSdkVersion 28
@ -89,6 +91,10 @@ dependencies {
implementation "com.mikepenz:fontawesome-typeface:5.9.0.0-kotlin@aar" implementation "com.mikepenz:fontawesome-typeface:5.9.0.0-kotlin@aar"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
implementation "com.google.dagger:dagger:$daggerVersion"
implementation 'androidx.navigation:navigation-fragment:2.0.0-rc02' implementation 'androidx.navigation:navigation-fragment:2.0.0-rc02'
implementation 'androidx.navigation:navigation-ui:2.0.0-rc02' implementation 'androidx.navigation:navigation-ui:2.0.0-rc02'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'

View File

@ -9,15 +9,14 @@ import androidx.appcompat.widget.Toolbar
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import com.github.clans.fab.FloatingActionMenu import com.github.clans.fab.FloatingActionMenu
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import net.dankito.banking.fints4java.android.di.BankingComponent
import net.dankito.banking.fints4java.android.di.BankingModule
import net.dankito.banking.fints4java.android.di.DaggerBankingComponent
import net.dankito.banking.fints4java.android.ui.views.DrawerView import net.dankito.banking.fints4java.android.ui.views.DrawerView
import net.dankito.banking.fints4java.android.ui.views.MainActivityFloatingActionMenuButton 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.presenter.BankingPresenter import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.utils.web.client.OkHttpWebClient
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.File import javax.inject.Inject
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@ -36,20 +35,28 @@ class MainActivity : AppCompatActivity() {
private lateinit var floatingActionMenuButton: MainActivityFloatingActionMenuButton private lateinit var floatingActionMenuButton: MainActivityFloatingActionMenuButton
lateinit var presenter: BankingPresenter @Inject
protected lateinit var presenter: BankingPresenter
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val dataFolder = File(this.filesDir, "data/accounts") setupDependencyInjection()
presenter = BankingPresenter(fints4javaBankingClientCreator(OkHttpWebClient(), Base64ServiceAndroid()), dataFolder, BankingComponent.component.inject(this)
BankingPersistenceJson(File(dataFolder, "accounts.json")), RouterAndroid(this))
initUi() initUi()
} }
private fun setupDependencyInjection() {
val component = DaggerBankingComponent.builder()
.bankingModule(BankingModule(this))
.build()
BankingComponent.component = component
}
private fun initUi() { private fun initUi() {
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)

View File

@ -21,7 +21,7 @@ import java.util.concurrent.atomic.AtomicReference
open class RouterAndroid(protected val activity: AppCompatActivity) : IRouter { open class RouterAndroid(protected val activity: AppCompatActivity) : IRouter {
override fun showAddAccountDialog(presenter: BankingPresenter) { override fun showAddAccountDialog(presenter: BankingPresenter) {
AddAccountDialog().show(activity, presenter) AddAccountDialog().show(activity)
} }
override fun getTanFromUserFromNonUiThread(account: Account, tanChallenge: TanChallenge, presenter: BankingPresenter): EnterTanResult { override fun getTanFromUserFromNonUiThread(account: Account, tanChallenge: TanChallenge, presenter: BankingPresenter): EnterTanResult {
@ -29,7 +29,7 @@ open class RouterAndroid(protected val activity: AppCompatActivity) : IRouter {
val tanEnteredLatch = CountDownLatch(1) val tanEnteredLatch = CountDownLatch(1)
activity.runOnUiThread { activity.runOnUiThread {
EnterTanDialog().show(account, tanChallenge, presenter, activity, false) { EnterTanDialog().show(account, tanChallenge, activity, false) {
enteredTan.set(it) enteredTan.set(it)
tanEnteredLatch.countDown() tanEnteredLatch.countDown()
} }
@ -57,7 +57,7 @@ open class RouterAndroid(protected val activity: AppCompatActivity) : IRouter {
} }
override fun showTransferMoneyDialog(presenter: BankingPresenter, preselectedBankAccount: BankAccount?, preselectedValues: TransferMoneyData?) { override fun showTransferMoneyDialog(presenter: BankingPresenter, preselectedBankAccount: BankAccount?, preselectedValues: TransferMoneyData?) {
TransferMoneyDialog().show(activity, presenter, preselectedBankAccount, preselectedValues) TransferMoneyDialog().show(activity, preselectedBankAccount, preselectedValues)
} }
} }

View File

@ -0,0 +1,31 @@
package net.dankito.banking.fints4java.android.di
import dagger.Component
import net.dankito.banking.fints4java.android.MainActivity
import net.dankito.banking.fints4java.android.ui.dialogs.AddAccountDialog
import net.dankito.banking.fints4java.android.ui.dialogs.EnterTanDialog
import net.dankito.banking.fints4java.android.ui.dialogs.TransferMoneyDialog
import net.dankito.banking.fints4java.android.ui.home.HomeFragment
import javax.inject.Singleton
@Singleton
@Component(modules = arrayOf(BankingModule::class))
interface BankingComponent {
companion object {
lateinit var component: BankingComponent
}
fun inject(mainActivity: MainActivity)
fun inject(homeFragment: HomeFragment)
fun inject(addAccountDialog: AddAccountDialog)
fun inject(enterTanDialog: EnterTanDialog)
fun inject(transferMoneyDialog: TransferMoneyDialog)
}

View File

@ -0,0 +1,103 @@
package net.dankito.banking.fints4java.android.di
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import dagger.Module
import dagger.Provides
import net.dankito.banking.fints4java.android.RouterAndroid
import net.dankito.banking.fints4java.android.util.Base64ServiceAndroid
import net.dankito.banking.fints4javaBankingClientCreator
import net.dankito.banking.persistence.BankingPersistenceJson
import net.dankito.banking.persistence.IBankingPersistence
import net.dankito.banking.ui.IBankingClientCreator
import net.dankito.banking.ui.IRouter
import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.utils.IThreadPool
import net.dankito.utils.ThreadPool
import net.dankito.utils.serialization.ISerializer
import net.dankito.utils.serialization.JacksonJsonSerializer
import net.dankito.utils.web.client.IWebClient
import net.dankito.utils.web.client.OkHttpWebClient
import java.io.File
import javax.inject.Named
import javax.inject.Singleton
@Module
class BankingModule(internal val mainActivity: AppCompatActivity) {
companion object {
const val DataFolderKey = "data.folder"
}
private val applicationContext = mainActivity.applicationContext
@Provides
@Singleton
fun provideApplicationContext() : Context {
return applicationContext
}
@Provides
@Singleton
@Named(DataFolderKey)
fun provideDataFolder(applicationContext: Context) : File {
return File(applicationContext.filesDir, "data/accounts")
}
@Provides
@Singleton
fun provideBankingPresenter(bankingClientCreator: IBankingClientCreator, @Named(DataFolderKey) dataFolder: File,
persister: IBankingPersistence, router: IRouter, threadPool: IThreadPool) : BankingPresenter {
return BankingPresenter(bankingClientCreator, dataFolder, persister, router, threadPool)
}
@Provides
@Singleton
fun provideBankingClientCreator(webClient: IWebClient, base64Service: net.dankito.banking.util.IBase64Service) : IBankingClientCreator {
return fints4javaBankingClientCreator(webClient, base64Service)
}
@Provides
@Singleton
fun provideBankingPersistence(@Named(DataFolderKey) dataFolder: File, serializer: ISerializer) : IBankingPersistence {
return BankingPersistenceJson(File(dataFolder, "accounts.json"), serializer)
}
@Provides
@Singleton
fun provideRouter() : IRouter {
return RouterAndroid(mainActivity)
}
@Provides
@Singleton
fun provideWebClient() : IWebClient {
return OkHttpWebClient()
}
@Provides
@Singleton
fun provideSerializer() : ISerializer {
return JacksonJsonSerializer()
}
@Provides
@Singleton
fun provideBase64Service() : net.dankito.banking.util.IBase64Service {
return Base64ServiceAndroid()
}
@Provides
@Singleton
fun provideThreadPool() : IThreadPool {
return ThreadPool()
}
}

View File

@ -19,11 +19,13 @@ import com.otaliastudios.autocomplete.AutocompleteCallback
import kotlinx.android.synthetic.main.dialog_add_account.* import kotlinx.android.synthetic.main.dialog_add_account.*
import kotlinx.android.synthetic.main.dialog_add_account.view.* import kotlinx.android.synthetic.main.dialog_add_account.view.*
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.di.BankingComponent
import net.dankito.banking.fints4java.android.ui.adapter.presenter.BankInfoPresenter import net.dankito.banking.fints4java.android.ui.adapter.presenter.BankInfoPresenter
import net.dankito.banking.ui.model.responses.AddAccountResponse import net.dankito.banking.ui.model.responses.AddAccountResponse
import net.dankito.banking.ui.presenter.BankingPresenter import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.fints.model.BankInfo import net.dankito.fints.model.BankInfo
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
import javax.inject.Inject
open class AddAccountDialog : DialogFragment() { open class AddAccountDialog : DialogFragment() {
@ -33,16 +35,21 @@ open class AddAccountDialog : DialogFragment() {
} }
protected lateinit var presenter: BankingPresenter
protected var selectedBank: BankInfo? = null protected var selectedBank: BankInfo? = null
fun show(activity: AppCompatActivity, presenter: BankingPresenter, fullscreen: Boolean = false) { @Inject
this.presenter = presenter protected lateinit var presenter: BankingPresenter
init {
BankingComponent.component.inject(this)
presenter.preloadBanksAsync() presenter.preloadBanksAsync()
}
fun show(activity: AppCompatActivity, fullscreen: Boolean = false) {
val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
setStyle(STYLE_NORMAL, style) setStyle(STYLE_NORMAL, style)

View File

@ -15,6 +15,7 @@ import androidx.fragment.app.DialogFragment
import kotlinx.android.synthetic.main.dialog_enter_tan.view.* import kotlinx.android.synthetic.main.dialog_enter_tan.view.*
import kotlinx.android.synthetic.main.view_tan_image.view.* import kotlinx.android.synthetic.main.view_tan_image.view.*
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.di.BankingComponent
import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter
import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter
import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener
@ -22,6 +23,7 @@ import net.dankito.banking.ui.model.Account
import net.dankito.banking.ui.model.responses.BankingClientResponse import net.dankito.banking.ui.model.responses.BankingClientResponse
import net.dankito.banking.ui.model.tan.* import net.dankito.banking.ui.model.tan.*
import net.dankito.banking.ui.presenter.BankingPresenter import net.dankito.banking.ui.presenter.BankingPresenter
import javax.inject.Inject
open class EnterTanDialog : DialogFragment() { open class EnterTanDialog : DialogFragment() {
@ -37,19 +39,25 @@ open class EnterTanDialog : DialogFragment() {
protected lateinit var tanChallenge: TanChallenge protected lateinit var tanChallenge: TanChallenge
protected lateinit var presenter: BankingPresenter
protected lateinit var tanEnteredCallback: (EnterTanResult) -> Unit protected lateinit var tanEnteredCallback: (EnterTanResult) -> Unit
protected val tanMediumAdapter = TanMediumAdapter() protected val tanMediumAdapter = TanMediumAdapter()
open fun show(account: Account, tanChallenge: TanChallenge, presenter: BankingPresenter, activity: AppCompatActivity, @Inject
protected lateinit var presenter: BankingPresenter
init {
BankingComponent.component.inject(this)
}
open fun show(account: Account, tanChallenge: TanChallenge, activity: AppCompatActivity,
fullscreen: Boolean = false, tanEnteredCallback: (EnterTanResult) -> Unit) { fullscreen: Boolean = false, tanEnteredCallback: (EnterTanResult) -> Unit) {
this.account = account this.account = account
this.tanChallenge = tanChallenge this.tanChallenge = tanChallenge
this.presenter = presenter
this.tanEnteredCallback = tanEnteredCallback this.tanEnteredCallback = tanEnteredCallback
val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog

View File

@ -12,6 +12,7 @@ import androidx.fragment.app.DialogFragment
import kotlinx.android.synthetic.main.dialog_transfer_money.* import kotlinx.android.synthetic.main.dialog_transfer_money.*
import kotlinx.android.synthetic.main.dialog_transfer_money.view.* import kotlinx.android.synthetic.main.dialog_transfer_money.view.*
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.di.BankingComponent
import net.dankito.banking.fints4java.android.ui.adapter.BankAccountsAdapter import net.dankito.banking.fints4java.android.ui.adapter.BankAccountsAdapter
import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener
import net.dankito.banking.fints4java.android.util.StandardTextWatcher import net.dankito.banking.fints4java.android.util.StandardTextWatcher
@ -24,6 +25,7 @@ import net.dankito.fints.model.BankInfo
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
import java.math.BigDecimal import java.math.BigDecimal
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols
import javax.inject.Inject
open class TransferMoneyDialog : DialogFragment() { open class TransferMoneyDialog : DialogFragment() {
@ -33,8 +35,6 @@ open class TransferMoneyDialog : DialogFragment() {
} }
protected lateinit var presenter: BankingPresenter
protected var preselectedBankAccount: BankAccount? = null protected var preselectedBankAccount: BankAccount? = null
protected lateinit var bankAccount: BankAccount protected lateinit var bankAccount: BankAccount
@ -47,12 +47,20 @@ open class TransferMoneyDialog : DialogFragment() {
protected var foundBankForEnteredIban = false protected var foundBankForEnteredIban = false
open fun show(activity: AppCompatActivity, presenter: BankingPresenter, preselectedBankAccount: BankAccount?, fullscreen: Boolean = false) { @Inject
show(activity, presenter, preselectedBankAccount, null, fullscreen) protected lateinit var presenter: BankingPresenter
init {
BankingComponent.component.inject(this)
} }
open fun show(activity: AppCompatActivity, presenter: BankingPresenter, preselectedBankAccount: BankAccount?, preselectedValues: TransferMoneyData?, fullscreen: Boolean = false) {
this.presenter = presenter open fun show(activity: AppCompatActivity, preselectedBankAccount: BankAccount?, fullscreen: Boolean = false) {
show(activity, preselectedBankAccount, null, fullscreen)
}
open fun show(activity: AppCompatActivity, preselectedBankAccount: BankAccount?, preselectedValues: TransferMoneyData?, fullscreen: Boolean = false) {
this.preselectedBankAccount = preselectedBankAccount this.preselectedBankAccount = preselectedBankAccount
this.preselectedValues = preselectedValues this.preselectedValues = preselectedValues

View File

@ -12,14 +12,15 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import net.dankito.banking.fints4java.android.MainActivity
import net.dankito.banking.fints4java.android.R import net.dankito.banking.fints4java.android.R
import net.dankito.banking.fints4java.android.di.BankingComponent
import net.dankito.banking.fints4java.android.ui.adapter.AccountTransactionAdapter import net.dankito.banking.fints4java.android.ui.adapter.AccountTransactionAdapter
import net.dankito.banking.ui.model.AccountTransaction import net.dankito.banking.ui.model.AccountTransaction
import net.dankito.banking.ui.model.parameters.TransferMoneyData import net.dankito.banking.ui.model.parameters.TransferMoneyData
import net.dankito.banking.ui.model.responses.GetTransactionsResponse import net.dankito.banking.ui.model.responses.GetTransactionsResponse
import net.dankito.banking.ui.presenter.BankingPresenter import net.dankito.banking.ui.presenter.BankingPresenter
import net.dankito.utils.android.extensions.asActivity import net.dankito.utils.android.extensions.asActivity
import javax.inject.Inject
class HomeFragment : Fragment() { class HomeFragment : Fragment() {
@ -38,7 +39,13 @@ class HomeFragment : Fragment() {
protected var appliedTransactionsFilter = "" protected var appliedTransactionsFilter = ""
private lateinit var presenter: BankingPresenter @Inject
protected lateinit var presenter: BankingPresenter
init {
BankingComponent.component.inject(this)
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -62,8 +69,6 @@ class HomeFragment : Fragment() {
registerForContextMenu(rcyvwAccountTransactions) // this is actually bad, splits code as context menu is created in AccountTransactionAdapter registerForContextMenu(rcyvwAccountTransactions) // this is actually bad, splits code as context menu is created in AccountTransactionAdapter
initLogic()
return root return root
} }
@ -122,14 +127,6 @@ class HomeFragment : Fragment() {
} }
private fun initLogic() {
// TODO: this is such a bad code style
(context as? MainActivity)?.presenter?.let { presenter ->
this.presenter = presenter
}
}
private fun initLogicAfterUiInitialized() { private fun initLogicAfterUiInitialized() {
presenter.addSelectedBankAccountsChangedListener { handleSelectedBankAccountsChanged() } presenter.addSelectedBankAccountsChangedListener { handleSelectedBankAccountsChanged() }