fix: Prevent crash when showing account chooser (#1117)
Chooser dialog could start before any accounts have loaded. Fix by collecting the account flow and waiting for the first emission (convert the flow to shared instead of state so there's no initial empty list). Guard against the potential for a similar issue when fetching notifications. Order the list of accounts with active account first so that code that skips it by ignoring the first item works correctly.
This commit is contained in:
parent
5c048311b2
commit
632282d0e2
|
@ -40,6 +40,8 @@ import kotlin.collections.set
|
|||
import kotlin.math.min
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.take
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
|
@ -57,11 +59,11 @@ class NotificationFetcher @Inject constructor(
|
|||
@ApplicationContext private val context: Context,
|
||||
) {
|
||||
suspend fun fetchAndShow(pachliAccountId: Long) {
|
||||
Timber.d("NotificationFetcher.fetchAndShow() started")
|
||||
Timber.d("NotificationFetcher.fetchAndShow(%d) started", pachliAccountId)
|
||||
|
||||
val accounts = buildList {
|
||||
if (pachliAccountId == NotificationWorker.ALL_ACCOUNTS) {
|
||||
addAll(accountManager.accountsOrderedByActive)
|
||||
addAll(accountManager.accountsOrderedByActiveFlow.take(1).first())
|
||||
} else {
|
||||
accountManager.getAccountById(pachliAccountId)?.let { add(it) }
|
||||
}
|
||||
|
@ -69,7 +71,7 @@ class NotificationFetcher @Inject constructor(
|
|||
|
||||
for (account in accounts) {
|
||||
Timber.d(
|
||||
"Checking %s$, notificationsEnabled = %s",
|
||||
"Checking %s, notificationsEnabled = %s",
|
||||
account.fullName,
|
||||
account.notificationsEnabled,
|
||||
)
|
||||
|
|
|
@ -59,6 +59,8 @@ import dagger.hilt.android.EntryPointAccessors.fromApplication
|
|||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Inject
|
||||
import kotlin.properties.Delegates
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.take
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
|
@ -229,17 +231,26 @@ abstract class BaseActivity : AppCompatActivity(), MenuProvider {
|
|||
bar.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a dialog allowing the user to choose from the available accounts.
|
||||
*
|
||||
* @param dialogTitle
|
||||
* @parma showActiveAccount True if the active account should be included in
|
||||
* the list of accounts.
|
||||
* @parma listener
|
||||
*/
|
||||
fun showAccountChooserDialog(
|
||||
dialogTitle: CharSequence?,
|
||||
showActiveAccount: Boolean,
|
||||
listener: AccountSelectionListener,
|
||||
) {
|
||||
val accounts = accountManager.accountsOrderedByActive.toMutableList()
|
||||
lifecycleScope.launch {
|
||||
val accounts = accountManager.accountsOrderedByActiveFlow.take(1).first().toMutableList()
|
||||
val activeAccount = accounts.first()
|
||||
when (accounts.size) {
|
||||
1 -> {
|
||||
listener.onAccountSelected(activeAccount)
|
||||
return
|
||||
return@launch
|
||||
}
|
||||
|
||||
2 -> {
|
||||
|
@ -247,7 +258,7 @@ abstract class BaseActivity : AppCompatActivity(), MenuProvider {
|
|||
for (account in accounts) {
|
||||
if (activeAccount !== account) {
|
||||
listener.onAccountSelected(account)
|
||||
return
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,20 +268,19 @@ abstract class BaseActivity : AppCompatActivity(), MenuProvider {
|
|||
accounts.remove(activeAccount)
|
||||
}
|
||||
val adapter = AccountSelectionAdapter(
|
||||
this,
|
||||
this@BaseActivity,
|
||||
sharedPreferencesRepository.animateAvatars,
|
||||
sharedPreferencesRepository.animateEmojis,
|
||||
)
|
||||
adapter.addAll(accounts)
|
||||
AlertDialog.Builder(this)
|
||||
AlertDialog.Builder(this@BaseActivity)
|
||||
.setTitle(dialogTitle)
|
||||
.setAdapter(adapter) { _: DialogInterface?, index: Int ->
|
||||
listener.onAccountSelected(
|
||||
accounts[index],
|
||||
)
|
||||
listener.onAccountSelected(accounts[index])
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
val openAsText: String?
|
||||
get() {
|
||||
|
|
|
@ -68,6 +68,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
|
|||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
@ -190,11 +191,11 @@ class AccountManager @Inject constructor(
|
|||
val accounts: List<AccountEntity>
|
||||
get() = accountsFlow.value
|
||||
|
||||
private val accountsOrderedByActiveFlow = accountDao.getAccountsOrderedByActive()
|
||||
.stateIn(externalScope, SharingStarted.Eagerly, emptyList())
|
||||
val accountsOrderedByActiveFlow = accountDao.getAccountsOrderedByActive()
|
||||
.shareIn(externalScope, SharingStarted.Eagerly, replay = 1)
|
||||
|
||||
val accountsOrderedByActive: List<AccountEntity>
|
||||
get() = accountsOrderedByActiveFlow.value
|
||||
get() = accountsOrderedByActiveFlow.replayCache.first()
|
||||
|
||||
@Deprecated("Caller should use getPachliAccountFlow with a specific account ID")
|
||||
val activePachliAccountFlow = accountDao.getActivePachliAccountFlow()
|
||||
|
|
|
@ -86,7 +86,7 @@ interface AccountDao {
|
|||
"""
|
||||
SELECT *
|
||||
FROM AccountEntity
|
||||
ORDER BY isActive, id ASC
|
||||
ORDER BY isActive DESC, id ASC
|
||||
""",
|
||||
)
|
||||
fun getAccountsOrderedByActive(): Flow<List<AccountEntity>>
|
||||
|
|
Loading…
Reference in New Issue