Replace the rest of the bus with channels and remove EventBus

This commit is contained in:
ligi 2020-03-01 03:42:53 +01:00
parent 6c5298b071
commit f0485d7865
No known key found for this signature in database
GPG key ID: 8E81894010ABF23D
17 changed files with 73 additions and 110 deletions

View file

@ -137,7 +137,6 @@ dependencies {
implementation 'com.github.ligi:ExtraCompats:1.0'
implementation 'net.lingala.zip4j:zip4j:2.3.2'
implementation 'com.jakewharton.threetenabp:threetenabp:1.2.2'
implementation 'org.greenrobot:eventbus:3.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'

View file

@ -1,6 +1,5 @@
package org.ligi.passandroid
import org.greenrobot.eventbus.EventBus
import org.koin.core.module.Module
import org.koin.dsl.module
import org.ligi.passandroid.injections.FixedPassListPassStore
@ -24,7 +23,6 @@ class TestApp : App() {
single { passStore as PassStore }
single { settings }
single { tracker }
single { mock(EventBus::class.java) }
}
}

View file

@ -84,6 +84,7 @@ class TheBarCodeEditing {
onView(withText(passBarCodeFormat.name)).perform(scrollTo(), click())
onView(withId(R.id.randomButton)).perform(click())
closeSoftKeyboard()
onView(withText(android.R.string.ok)).perform(click())

View file

@ -1,7 +1,10 @@
package org.ligi.passandroid.injections
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
import org.ligi.passandroid.model.PassClassifier
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.PassStoreUpdateEvent
import org.ligi.passandroid.model.pass.Pass
import java.io.File
@ -48,6 +51,8 @@ class FixedPassListPassStore(private var passes: List<Pass>) : PassStore {
return File("")
}
override val updateChannel: BroadcastChannel<PassStoreUpdateEvent> = ConflatedBroadcastChannel()
override fun save(pass: Pass) {
// no effect in this impl
}

View file

@ -4,7 +4,6 @@ import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.jakewharton.threetenabp.AndroidThreeTen
import com.squareup.moshi.Moshi
import org.greenrobot.eventbus.EventBus
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
@ -32,9 +31,8 @@ open class App : Application() {
open fun createKoin(): Module {
return module {
single { AndroidFileSystemPassStore(this@App, get(), moshi, get()) as PassStore }
single { AndroidFileSystemPassStore(this@App, get(), moshi) as PassStore }
single { settings as Settings }
single { EventBus.getDefault() }
single { createTracker(this@App) }
single { PassScanEventChannelProvider() }
}

View file

@ -1,5 +0,0 @@
package org.ligi.passandroid.events
import org.ligi.passandroid.model.pass.Pass
class PassRefreshEvent(val pass: Pass)

View file

@ -1,3 +0,0 @@
package org.ligi.passandroid.events
object PassStoreChangeEvent

View file

@ -3,15 +3,16 @@ package org.ligi.passandroid.model
import android.content.Context
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.Moshi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
import kotlinx.coroutines.launch
import okio.buffer
import okio.sink
import okio.source
import org.greenrobot.eventbus.EventBus
import org.koin.core.KoinComponent
import org.koin.core.inject
import org.ligi.passandroid.BuildConfig
import org.ligi.passandroid.Tracker
import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.model.pass.PassImpl
import org.ligi.passandroid.reader.AppleStylePassReader
@ -19,18 +20,23 @@ import org.ligi.passandroid.reader.PassReader
import java.io.File
import java.util.*
object PassStoreUpdateEvent
class AndroidFileSystemPassStore(
private val context: Context, settings: Settings,
private val moshi: Moshi,
private val bus: EventBus
private val context: Context,
settings: Settings,
private val moshi: Moshi
) : PassStore, KoinComponent {
override val updateChannel = ConflatedBroadcastChannel<PassStoreUpdateEvent>()
private val path: File = settings.getPassesDir()
override val passMap = HashMap<String, Pass>()
override var currentPass: Pass? = null
private val tracker: Tracker by inject ()
private val tracker: Tracker by inject()
override val classifier: PassClassifier by lazy {
val classificationFile = File(settings.getStateDir(), "classifier_state.json")
@ -122,7 +128,9 @@ class AndroidFileSystemPassStore(
}
override fun notifyChange() {
bus.post(PassStoreChangeEvent)
GlobalScope.launch {
updateChannel.send(PassStoreUpdateEvent)
}
}
override fun syncPassStoreWithClassifier(defaultTopic: String) {

View file

@ -1,10 +1,13 @@
package org.ligi.passandroid.model
import kotlinx.coroutines.channels.BroadcastChannel
import org.ligi.passandroid.model.pass.Pass
import java.io.File
interface PassStore {
val updateChannel: BroadcastChannel<PassStoreUpdateEvent>
fun save(pass: Pass)
fun getPassbookForId(id: String): Pass?

View file

@ -1,7 +1,6 @@
package org.ligi.passandroid.ui
import androidx.appcompat.app.AppCompatActivity
import org.greenrobot.eventbus.EventBus
import org.koin.android.ext.android.inject
import org.ligi.passandroid.Tracker
import org.ligi.passandroid.model.PassStore
@ -11,7 +10,6 @@ open class PassAndroidActivity : AppCompatActivity() {
val passStore: PassStore by inject()
val settings: Settings by inject()
val bus: EventBus by inject()
val tracker: Tracker by inject()
private var lastSetNightMode: Int? = null

View file

@ -11,12 +11,9 @@ import androidx.annotation.IdRes
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.edit.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.koin.android.ext.android.inject
import org.ligi.kaxt.doAfterEdit
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassRefreshEvent
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.pass.BarCode
import org.ligi.passandroid.model.pass.Pass
@ -39,7 +36,6 @@ class PassEditActivity : AppCompatActivity() {
private val imageEditHelper by lazy { ImageEditHelper(this, passStore) }
internal val passStore: PassStore by inject()
internal val bus: EventBus by inject()
private val passViewHelper: PassViewHelper by lazy { PassViewHelper(this) }
@ -56,8 +52,8 @@ class PassEditActivity : AppCompatActivity() {
categoryView.setOnClickListener {
AlertDialog.Builder(this).setItems(R.array.category_edit_options) { _, i ->
when (i) {
0 -> showCategoryPickDialog(this@PassEditActivity, currentPass, bus)
1 -> showColorPickDialog(this@PassEditActivity, currentPass, bus)
0 -> showCategoryPickDialog(this@PassEditActivity, currentPass, refreshCallback)
1 -> showColorPickDialog(this@PassEditActivity, currentPass, refreshCallback)
2 -> pickImageWithPermissionCheck(ImageEditHelper.REQ_CODE_PICK_ICON)
}
}.show()
@ -84,17 +80,15 @@ class PassEditActivity : AppCompatActivity() {
add_barcode_button.setOnClickListener {
showBarcodeEditDialog(this@PassEditActivity,
bus,
refreshCallback,
this@PassEditActivity.currentPass,
BarCode(PassBarCodeFormat.QR_CODE, UUID.randomUUID().toString().toUpperCase()))
}
}
val refreshCallback = { refresh(currentPass) }
@Subscribe
fun onPassRefresh(event: PassRefreshEvent) {
refresh(currentPass)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
@ -117,7 +111,7 @@ class PassEditActivity : AppCompatActivity() {
add_barcode_button.visibility = if (pass.barCode == null) View.VISIBLE else View.GONE
val barcodeUIController = BarcodeUIController(window.decorView, pass.barCode, this, passViewHelper)
barcodeUIController.getBarcodeView().setOnClickListener { showBarcodeEditDialog(this@PassEditActivity, bus, currentPass, currentPass.barCode!!) }
barcodeUIController.getBarcodeView().setOnClickListener { showBarcodeEditDialog(this@PassEditActivity, refreshCallback, currentPass, currentPass.barCode!!) }
}
@Pass.PassBitmap
@ -141,13 +135,11 @@ class PassEditActivity : AppCompatActivity() {
override fun onResumeFragments() {
super.onResumeFragments()
bus.register(this)
refresh(currentPass)
}
override fun onPause() {
bus.unregister(this)
passStore.save(currentPass)
passStore.notifyChange()
super.onPause()

View file

@ -15,15 +15,14 @@ import android.view.View.VISIBLE
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.core.view.GravityCompat
import androidx.lifecycle.lifecycleScope
import androidx.viewpager.widget.ViewPager
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.pass_list.*
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlinx.coroutines.launch
import org.ligi.kaxt.startActivityFromClass
import org.ligi.kaxt.startActivityFromURL
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.functions.createAndAddEmptyPass
import org.ligi.passandroid.model.PassStoreProjection
import org.ligi.passandroid.model.State
@ -135,7 +134,7 @@ class PassListActivity : PassAndroidActivity() {
})
passStore.syncPassStoreWithClassifier(getString(R.string.topic_new))
onPassStoreChangeEvent(null)
refresh()
fab_action_create_pass.setOnClickListener {
val pass = createAndAddEmptyPass(passStore, resources)
@ -168,9 +167,29 @@ class PassListActivity : PassAndroidActivity() {
}
fab_action_open_file.visibility = VISIBLE
}
lifecycleScope.launch {
for (update in passStore.updateChannel.openSubscription()) {
navigationView.passStoreUpdate()
refresh()
}
}
}
fun refresh() {
adapter.notifyDataSetChanged()
setupWithViewPagerIfNeeded()
invalidateOptionsMenu()
val empty = passStore.classifier.topicByIdMap.isEmpty()
emptyView.visibility = if (empty) VISIBLE else GONE
val onlyDefaultTopicExists = passStore.classifier.getTopics().all { it == getString(R.string.topic_new) }
tab_layout.visibility = if (onlyDefaultTopicExists) GONE else VISIBLE
}
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.menu_help -> {
startActivityFromClass(HelpActivity::class.java)
@ -199,10 +218,8 @@ class PassListActivity : PassAndroidActivity() {
override fun onResume() {
super.onResume()
bus.register(this)
adapter.notifyDataSetChanged()
onPassStoreChangeEvent(null)
refresh()
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
@ -225,25 +242,6 @@ class PassListActivity : PassAndroidActivity() {
drawerToggle.onConfigurationChanged(newConfig)
}
override fun onPause() {
bus.unregister(this)
super.onPause()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onPassStoreChangeEvent(passStoreChangeEvent: PassStoreChangeEvent?) {
adapter.notifyDataSetChanged()
setupWithViewPagerIfNeeded()
invalidateOptionsMenu()
val empty = passStore.classifier.topicByIdMap.isEmpty()
emptyView.visibility = if (empty) VISIBLE else GONE
val onlyDefaultTopicExists = passStore.classifier.getTopics().all { it == getString(R.string.topic_new) }
tab_layout.visibility = if (onlyDefaultTopicExists) GONE else VISIBLE
}
private fun setupWithViewPagerIfNeeded() {
if (!areTabLayoutAndViewPagerInSync()) {
tab_layout.setupWithViewPager(view_pager)

View file

@ -7,18 +7,16 @@ import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.*
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import kotlinx.android.synthetic.main.pass_recycler.view.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.functions.moveWithUndoSnackbar
import org.ligi.passandroid.model.PassStore
import org.ligi.passandroid.model.PassStoreProjection
@ -31,7 +29,6 @@ class PassListFragment : Fragment() {
val passStore: PassStore by inject()
val settings: Settings by inject()
val bus: EventBus by inject()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val inflate = inflater.inflate(R.layout.pass_recycler, container, false)
@ -56,7 +53,12 @@ class PassListFragment : Fragment() {
val itemTouchHelper = ItemTouchHelper(simpleItemTouchCallback)
itemTouchHelper.attachToRecyclerView(inflate.pass_recyclerview)
bus.register(this)
lifecycleScope.launch {
for (update in passStore.updateChannel.openSubscription()) {
passStoreProjection.refresh()
adapter.notifyDataSetChanged()
}
}
return inflate
}
@ -74,17 +76,6 @@ class PassListFragment : Fragment() {
}
}
override fun onDestroyView() {
super.onDestroyView()
bus.unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onPassStoreChangeEvent(passStoreChangeEvent: PassStoreChangeEvent) {
passStoreProjection.refresh()
adapter.notifyDataSetChanged()
}
companion object {
private const val BUNDLE_KEY_TOPIC = "topic"

View file

@ -7,19 +7,14 @@ import android.net.Uri
import android.util.AttributeSet
import com.google.android.material.navigation.NavigationView
import kotlinx.android.synthetic.main.navigation_drawer_header.view.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.koin.core.KoinComponent
import org.koin.core.inject
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassStoreChangeEvent
import org.ligi.passandroid.model.PassStore
class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView(context, attrs), KoinComponent {
val passStore: PassStore by inject()
val bus: EventBus by inject()
private fun getIntent(id: Int) = when (id) {
R.id.menu_settings -> Intent(context, PreferenceActivity::class.java)
@ -39,8 +34,6 @@ class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView
override fun onAttachedToWindow() {
super.onAttachedToWindow()
bus.register(this)
setNavigationItemSelectedListener { item ->
getIntent(item.itemId)?.let {
context.startActivity(it)
@ -48,19 +41,12 @@ class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView
} ?: false
}
onPassStoreChangeEvent(PassStoreChangeEvent)
}
@SuppressLint("RestrictedApi") // FIXME: temporary workaround for false-positive
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
bus.unregister(this)
passStoreUpdate()
}
private val marketUrl by lazy { context.getString(R.string.market_url, context.packageName) }
@Subscribe(threadMode = ThreadMode.MAIN)
fun onPassStoreChangeEvent(@Suppress("UNUSED_PARAMETER") passStoreChangeEvent: PassStoreChangeEvent) {
fun passStoreUpdate() {
val passCount = passStore.passMap.size
getHeaderView(0).pass_count_header.text = context.getString(R.string.passes_nav, passCount)

View file

@ -2,15 +2,13 @@ package org.ligi.passandroid.ui.edit.dialogs
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import org.greenrobot.eventbus.EventBus
import org.ligi.kaxt.inflate
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassRefreshEvent
import org.ligi.passandroid.model.pass.BarCode
import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.ui.edit.BarcodeEditController
fun showBarcodeEditDialog(context: AppCompatActivity, bus: EventBus, pass: Pass, barCode: BarCode) {
fun showBarcodeEditDialog(context: AppCompatActivity, refreshCallback: () -> Unit, pass: Pass, barCode: BarCode) {
val view = context.inflate(R.layout.barcode_edit)
val barcodeEditController = BarcodeEditController(view, context, barCode)
@ -20,7 +18,7 @@ fun showBarcodeEditDialog(context: AppCompatActivity, bus: EventBus, pass: Pass,
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok) { _, _ ->
pass.barCode = barcodeEditController.getBarCode()
bus.post(PassRefreshEvent(pass))
refreshCallback.invoke()
}
.show()
}

View file

@ -1,15 +1,13 @@
package org.ligi.passandroid.ui.edit.dialogs
import android.content.Context
import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
import org.greenrobot.eventbus.EventBus
import androidx.appcompat.app.AlertDialog
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassRefreshEvent
import org.ligi.passandroid.functions.getCategoryDefaultBG
import org.ligi.passandroid.functions.getHumanCategoryString
import org.ligi.passandroid.model.pass.Pass
@ -18,7 +16,7 @@ import org.ligi.passandroid.ui.views.BaseCategoryIndicatorView
private val passTypes = arrayOf(PassType.BOARDING, PassType.EVENT, PassType.GENERIC, PassType.LOYALTY, PassType.VOUCHER, PassType.COUPON)
fun showCategoryPickDialog(context: Context, pass: Pass, bus: EventBus) {
fun showCategoryPickDialog(context: Context, pass: Pass, refreshCallback: () -> Unit) {
val adapter = object : BaseAdapter() {
@ -47,7 +45,7 @@ fun showCategoryPickDialog(context: Context, pass: Pass, bus: EventBus) {
val builder = AlertDialog.Builder(context)
builder.setAdapter(adapter) { _, position ->
pass.type = passTypes[position]
bus.post(PassRefreshEvent(pass))
refreshCallback.invoke()
}
builder.setTitle(R.string.select_category_dialog_title)
builder.setNegativeButton(android.R.string.cancel, null)

View file

@ -1,21 +1,19 @@
package org.ligi.passandroid.ui.edit.dialogs
import android.content.Context
import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.edit_color.view.*
import org.greenrobot.eventbus.EventBus
import org.ligi.passandroid.R
import org.ligi.passandroid.events.PassRefreshEvent
import org.ligi.passandroid.model.pass.Pass
fun showColorPickDialog(context: Context, pass: Pass, bus: EventBus) {
fun showColorPickDialog(context: Context, pass: Pass, refreshCallback : () -> Unit) {
val inflate = LayoutInflater.from(context).inflate(R.layout.edit_color, null)
inflate.colorPicker.color = pass.accentColor
inflate.colorPicker.oldCenterColor = pass.accentColor
AlertDialog.Builder(context).setView(inflate).setPositiveButton(android.R.string.ok) { _, _ ->
pass.accentColor = inflate.colorPicker.color
bus.post(PassRefreshEvent(pass))
refreshCallback.invoke()
}.setNegativeButton(android.R.string.cancel, null).setTitle(R.string.change_color_dialog_title).show()
}