Refactored UserManager Current/User getters.

This commit is contained in:
Neil Marietta 2021-04-26 10:41:05 +02:00
parent 570b3cc443
commit 3528d236c1
52 changed files with 238 additions and 327 deletions

View File

@ -52,7 +52,7 @@ internal class NotificationSettingsViewModelTest {
every { ringtone = any() } answers { ringtoneUri = firstArg(); Unit }
}
return mockk(relaxed = true) {
every { this@mockk.user } returns user
every { this@mockk.currentLegacyUser } returns user
}
}
@ -66,10 +66,10 @@ internal class NotificationSettingsViewModelTest {
// @Test
fun mockUserManager_reliabilityTest() {
val userManager = mockUserManager(contentUri)
assertEquals(contentUri, userManager.user.ringtone)
assertEquals(contentUri, userManager.currentLegacyUser.ringtone)
userManager.user.ringtone = fileUri
assertEquals(fileUri, userManager.user.ringtone)
userManager.currentLegacyUser.ringtone = fileUri
assertEquals(fileUri, userManager.currentLegacyUser.ringtone)
}
// FIXME: Davide check this, it is causing a lot of test failures

View File

@ -51,7 +51,7 @@ class MailboxViewModelTest {
every { isPaidUser } returns false
}
private val mockUserManager = mockk<UserManager>(relaxed = true) {
every { user } returns mockUser
every { currentLegacyUser } returns mockUser
}
//private val mockResources = mockk<Resources>(relaxed = true) {
// val accountTypeNames = arrayOf("Free", "Plus", "Visionary", "Professional")

View File

@ -52,7 +52,6 @@ import ch.protonmail.android.events.Status;
import ch.protonmail.android.events.organizations.OrganizationEvent;
import ch.protonmail.android.jobs.organizations.GetOrganizationJob;
import ch.protonmail.android.usecase.model.FetchPaymentMethodsResult;
import ch.protonmail.android.utils.AppUtil;
import ch.protonmail.android.viewmodel.AccountTypeViewModel;
import timber.log.Timber;
@ -91,7 +90,7 @@ public class AccountTypeActivity extends BaseActivity {
}
viewModel = new ViewModelProvider(this).get(AccountTypeViewModel.class);
final User user = mUserManager.getUser();
final User user = mUserManager.getCurrentLegacyUser();
if (user != null) {
if (!user.isPaidUser()) {
setAccountType(0);
@ -250,7 +249,7 @@ public class AccountTypeActivity extends BaseActivity {
boolean success = false; // TODO: extras.getBoolean(BillingActivity.EXTRA_SUCCESS);
if (success) {
accountTypeProgress.setVisibility(View.VISIBLE);
final User user = mUserManager.getUser();
final User user = mUserManager.getCurrentLegacyUser();
if (!user.isPaidUser()) {
setAccountType(0);
} else {

View File

@ -224,7 +224,7 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
protected void onResume() {
super.onResume();
User user = mUserManager.getCurrentLegacyUserBlocking();
User user = mUserManager.getCurrentLegacyUser();
// Enable secure mode if screenshots are disabled, else disable it
if (isPreventingScreenshots() || user != null && user.isPreventTakingScreenshots()) {
@ -268,7 +268,7 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
}
private void shouldLock() {
User user = mUserManager.getCurrentLegacyUserBlocking();
User user = mUserManager.getCurrentLegacyUser();
if (user == null)
return;
@ -351,7 +351,7 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
super.onStop();
// Enable secure mode for hide content from recent if pin is enabled, else disable it so
// content will be visible in recent
User currentUser = mUserManager.getCurrentLegacyUserBlocking();
User currentUser = mUserManager.getCurrentLegacyUser();
if (currentUser != null && currentUser.isUsePin())
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
else getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
@ -372,7 +372,7 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
}
private void activateScreenProtector() {
User currentUser = mUserManager.getCurrentLegacyUserBlocking();
User currentUser = mUserManager.getCurrentLegacyUser();
if (currentUser != null && currentUser.isUsePin()) {
if (mScreenProtectorLayout != null) {
mScreenProtectorLayout.setVisibility(View.VISIBLE);
@ -381,13 +381,13 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
}
protected void saveLastInteraction() {
User user = mUserManager.getCurrentLegacyUserBlocking();
User user = mUserManager.getCurrentLegacyUser();
if (user != null) user.setLastInteraction(SystemClock.elapsedRealtime());
}
protected void checkDelinquency() {
ch.protonmail.android.domain.entity.user.User user =
mUserManager.requireCurrentUserBlocking();
ch.protonmail.android.domain.entity.user.User user = mUserManager.getCurrentUser();
if (user == null) return;
boolean areMailRoutesAccessible = user.getDelinquent().getMailRoutesAccessible();
if (!areMailRoutesAccessible && (alertDelinquency == null || !alertDelinquency.isShowing())) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
@ -435,9 +435,8 @@ public abstract class BaseActivity extends AppCompatActivity implements INetwork
}
protected void fetchOrganizationData() {
ch.protonmail.android.domain.entity.user.User user =
mUserManager.requireCurrentUserBlocking();
if (user.isPaidMailUser()) {
User user = mUserManager.getCurrentLegacyUser();
if (user != null && user.isPaidUser()) {
GetOrganizationJob getOrganizationJob = new GetOrganizationJob();
mJobManager.addJobInBackground(getOrganizationJob);
} else {

View File

@ -68,13 +68,13 @@ class DefaultAddressActivity : BaseActivity() {
selectedAddressRadioButton.isChecked = true
defaultAddress.text = mSelectedAddress!!.email
val user = mUserManager.user
val user = mUserManager.currentLegacyUser
val selectedAddress = mSelectedAddress
if (selectedAddress != null && user.defaultAddressId != selectedAddress.id) {
if (selectedAddress != null && user?.defaultAddressId != selectedAddress.id) {
// Add first the selected address.
val addressIds = mutableSetOf(selectedAddress.id)
// Add all other.
user.addresses.forEach { addressIds.add(it.id) }
user?.addresses?.forEach { addressIds.add(it.id) }
//
val job = UpdateSettingsJob(addressIds = addressIds.toList())
mJobManager.addJobInBackground(job)
@ -91,7 +91,7 @@ class DefaultAddressActivity : BaseActivity() {
actionBar?.setDisplayHomeAsUpEnabled(true)
mAvailableAddressesMap = HashMap()
mAllRadioButtons = ArrayList()
mUser = mUserManager.user
mUser = mUserManager.currentLegacyUser
addresses = ArrayList(mUser!!.addresses)
mInflater = LayoutInflater.from(this)
renderAddresses()

View File

@ -102,7 +102,7 @@ class MailboxViewModel @Inject constructor(
fun usedSpaceActionEvent(limitReachedFlow: Int) {
viewModelScope.launch {
userManager.setShowStorageLimitReached(true)
val user = userManager.getCurrentUser()
val user = userManager.currentUser
?: return@launch
val (usedSpace, totalSpace) = with(user.dedicatedSpace) { used.l.toLong() to total.l.toLong() }
val userMaxSpace = if (totalSpace == 0L) Long.MAX_VALUE else totalSpace

View File

@ -79,7 +79,6 @@ import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.activity_mailbox.*
import kotlinx.android.synthetic.main.drawer_header.*
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@ -219,12 +218,12 @@ abstract class NavigationActivity :
super.onCreate(savedInstanceState)
accountViewModel.state
.flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
.flowWithLifecycle(lifecycle, Lifecycle.State.CREATED)
.onEach {
when (it) {
is AccountViewModel.State.Processing,
is AccountViewModel.State.LoginClosed,
is AccountViewModel.State.AccountList -> Unit
is AccountViewModel.State.PrimaryExist -> Unit
is AccountViewModel.State.AccountNeeded -> {
startSplashActivity()
finish()
@ -233,7 +232,7 @@ abstract class NavigationActivity :
}.launchIn(lifecycleScope)
accountViewModel.onAccountSwitched()
.flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
.flowWithLifecycle(lifecycle, Lifecycle.State.CREATED)
.onEach { switch -> onAccountSwitched(switch) }
.launchIn(lifecycleScope)
}
@ -260,7 +259,7 @@ abstract class NavigationActivity :
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == RESULT_OK && requestCode == REQUEST_CODE_SNOOZED_NOTIFICATIONS) {
refreshDrawerHeader(checkNotNull(userManager.getCurrentUserBlocking()))
refreshDrawerHeader(checkNotNull(userManager.currentUser))
} else {
super.onActivityResult(requestCode, resultCode, data)
}
@ -271,7 +270,7 @@ abstract class NavigationActivity :
// Requested UserId match the current ?
intent.extras?.getString(EXTRA_USER_ID)?.let { extraUserId ->
val requestedUserId = UserId(extraUserId)
if (requestedUserId != accountViewModel.getPrimaryUserId().firstOrNull()) {
if (requestedUserId != accountViewModel.getPrimaryUserIdValue()) {
accountViewModel.switch(requestedUserId)
}
}
@ -314,7 +313,7 @@ abstract class NavigationActivity :
)
)
drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START)
setUpInitialDrawerItems(checkNotNull(userManager.getCurrentLegacyUserBlocking()).isUsePin)
setUpInitialDrawerItems(userManager.currentLegacyUser?.isUsePin ?: false)
refreshDrawer()
// LayoutManager set from xml
@ -339,7 +338,7 @@ abstract class NavigationActivity :
navigationViewModel.locationsUnreadLiveData().observe(this, LocationsMenuObserver())
lifecycleScope.launchWhenCreated {
refreshDrawerHeader(checkNotNull(userManager.getCurrentUser()))
userManager.currentUser?.let { refreshDrawerHeader(it) }
}
setupAccountsList()
@ -352,7 +351,7 @@ abstract class NavigationActivity :
lifecycleScope.launchWhenCreated {
val accounts = accountViewModel.getSortedAccounts().first().map { account ->
val id = Id(account.userId.id)
val user = userManager.getLegacyUserOrNull(id)
val user = userManager.getUserOrNull(id)
account.toDrawerUser(account.isReady(), counters[id] ?: 0, user)
}
accountsAdapter.items = accounts + DrawerUserModel.Footer
@ -456,7 +455,7 @@ abstract class NavigationActivity :
lifecycleScope.launchWhenCreated {
drawerHeader = drawerHeader?.copy(snoozeEnabled = enabled)
refreshDrawer()
refreshDrawerHeader(checkNotNull(userManager.getCurrentUser()))
refreshDrawerHeader(checkNotNull(userManager.currentUser))
setupAccountsList()
}
}
@ -480,7 +479,7 @@ abstract class NavigationActivity :
val next = userManager.getUser(nextLoggedInUserId)
getString(R.string.logout) to getString(R.string.logout_question_next_account, next.name.s)
} else {
val current = checkNotNull(userManager.getCurrentUser())
val current = checkNotNull(userManager.currentUser)
getString(R.string.log_out, current.name.s) to getString(R.string.logout_question)
}
@ -516,8 +515,8 @@ abstract class NavigationActivity :
Type.ARCHIVE, Type.STARRED, Type.DRAFTS, Type.SENT, Type.TRASH, Type.SPAM, Type.ALLMAIL ->
onOtherMailBox(type.drawerOptionType)
Type.LOCK -> {
val user = userManager.user
if (user.isUsePin && userManager.getMailboxPin() != null) {
val user = userManager.currentLegacyUser
if (user != null && user.isUsePin && userManager.getMailboxPin() != null) {
user.setManuallyLocked(true)
val pinIntent = AppUtil.decorInAppIntent(Intent(this, ValidatePinActivity::class.java))
startActivityForResult(pinIntent, REQUEST_CODE_VALIDATE_PIN)

View File

@ -133,7 +133,7 @@ public class ReportBugsActivity extends BaseActivity {
String appVersionName = String.format(getString(R.string.full_version_name_report_bugs), AppUtil.getAppVersionName(this), AppUtil.getAppVersionCode(this));
String title = mBugDescriptionTitle.getText().toString();
String description = mBugDescription.getText().toString();
User user = mUserManager.requireCurrentUserBlocking();
User user = mUserManager.requireCurrentUser();
String username = user.getName().getS();
String email = user.getAddresses().getPrimary().getEmail().getS();
mJobManager.addJobInBackground(new ReportBugsJob(OSName, OSVersion, client, appVersionName, title, description, username, email));

View File

@ -39,13 +39,13 @@ class SplashActivity : BaseActivity() {
super.onCreate(savedInstanceState)
accountViewModel.state
.flowWithLifecycle(lifecycle, Lifecycle.State.RESUMED)
.flowWithLifecycle(lifecycle, Lifecycle.State.CREATED)
.onEach {
when (it) {
is AccountViewModel.State.Processing -> Unit
is AccountViewModel.State.LoginClosed -> finish()
is AccountViewModel.State.AccountNeeded -> accountViewModel.login()
is AccountViewModel.State.AccountList -> {
is AccountViewModel.State.PrimaryExist -> {
startMailboxActivity()
finish()
}

View File

@ -724,7 +724,7 @@ public class ComposeMessageActivity
if (connectivity != Constants.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.getUser(),
mUserManager.requireCurrentLegacyUser(),
this,
null,
null,
@ -1179,7 +1179,7 @@ public class ComposeMessageActivity
subject = subject.replaceAll("\n", " ");
}
message.setSubject(subject);
User user = mUserManager.getUser();
User user = mUserManager.getCurrentLegacyUser();
if (!TextUtils.isEmpty(composeMessageViewModel.getMessageDataResult().getAddressId())) {
message.setAddressID(composeMessageViewModel.getMessageDataResult().getAddressId());
} else if (user != null) {
@ -1773,7 +1773,7 @@ public class ComposeMessageActivity
private boolean mSendingInProgress;
private void loadPMContacts() {
if (mUserManager.getUser().getCombinedContacts()) {
if (mUserManager.getCurrentLegacyUser().getCombinedContacts()) {
composeMessageViewModel.getMergedContactsLiveData().observe(this, messageRecipients -> {
mMessageRecipientViewAdapter.setData(messageRecipients);
});
@ -1787,7 +1787,7 @@ public class ComposeMessageActivity
composeMessageViewModel.getContactGroupsResult().observe(this, messageRecipients -> {
mMessageRecipientViewAdapter.setData(messageRecipients);
});
composeMessageViewModel.fetchContactGroups(mUserManager.getCurrentUserId());
composeMessageViewModel.fetchContactGroups(mUserManager.requireCurrentUserId());
composeMessageViewModel.getPmMessageRecipientsResult().observe(this, messageRecipients -> {
mMessageRecipientViewAdapter.setData(messageRecipients);
});
@ -1954,7 +1954,7 @@ public class ComposeMessageActivity
} else {
String previousSenderAddressId = composeMessageViewModel.getMessageDataResult().getAddressId();
if (TextUtils.isEmpty(previousSenderAddressId)) { // first switch from default address
previousSenderAddressId = mUserManager.getUser().getDefaultAddressId();
previousSenderAddressId = mUserManager.requireCurrentLegacyUser().getDefaultAddressId();
}
if (TextUtils.isEmpty(composeMessageViewModel.getOldSenderAddressId()) && !localAttachmentsListEmpty) {
@ -2097,15 +2097,14 @@ public class ComposeMessageActivity
Message localMessage = messageEvent.getContentIfNotHandled();
if (localMessage != null) {
User user = mUserManager.requireCurrentLegacyUser();
String aliasAddress = composeMessageViewModel.getMessageDataResult().getAddressEmailAlias();
MessageSender messageSender;
if (aliasAddress != null && aliasAddress.equals(mAddressesSpinner.getSelectedItem())) { // it's being sent by alias
messageSender = new MessageSender(mUserManager.getUser().getDisplayNameForAddress(composeMessageViewModel.getMessageDataResult().getAddressId()), composeMessageViewModel.getMessageDataResult().getAddressEmailAlias());
messageSender = new MessageSender(user.getDisplayNameForAddress(composeMessageViewModel.getMessageDataResult().getAddressId()), composeMessageViewModel.getMessageDataResult().getAddressEmailAlias());
} else {
Address nonAliasAddress;
try {
User user = mUserManager.getUser();
if (localMessage.getAddressID() != null) {
nonAliasAddress = user.getAddressById(localMessage.getAddressID());
} else { // fallback to default address if newly composed message has no addressId

View File

@ -616,7 +616,7 @@ class MailboxActivity :
startObservingUsedSpace()
// manually update the flags for preventing screenshots
if (isPreventingScreenshots || userManager.user.isPreventTakingScreenshots) {
if (isPreventingScreenshots || userManager.currentLegacyUser?.isPreventTakingScreenshots == true) {
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
@ -1001,7 +1001,7 @@ class MailboxActivity :
@Subscribe
fun onSettingsChangedEvent(event: SettingsChangedEvent) {
val user = userManager.requireCurrentUserBlocking()
val user = userManager.requireCurrentUser()
if (event.success) {
refreshDrawerHeader(user)
} else {
@ -1062,7 +1062,7 @@ class MailboxActivity :
@Subscribe
fun onUpdatesLoaded(event: FetchUpdatesEvent?) {
lifecycleScope.launchWhenCreated {
userManager.getCurrentUser()?.let { refreshDrawerHeader(it) }
userManager.currentUser?.let { refreshDrawerHeader(it) }
}
}

View File

@ -83,7 +83,6 @@ import ch.protonmail.android.jobs.PostSpamJob
import ch.protonmail.android.jobs.PostTrashJobV2
import ch.protonmail.android.jobs.PostUnreadJob
import ch.protonmail.android.jobs.ReportPhishingJob
import ch.protonmail.android.prefs.SecureSharedPreferences
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.CustomLocale
import ch.protonmail.android.utils.Event
@ -204,7 +203,7 @@ internal class MessageDetailsActivity :
messageRecipientUserId = intent.getStringExtra(EXTRA_MESSAGE_RECIPIENT_USER_ID)?.let(::Id)
messageRecipientUsername = intent.getStringExtra(EXTRA_MESSAGE_RECIPIENT_USERNAME)
isTransientMessage = intent.getBooleanExtra(EXTRA_TRANSIENT_MESSAGE, false)
val currentUser = mUserManager.requireCurrentUserBlocking()
val currentUser = mUserManager.requireCurrentUser()
AppUtil.clearNotifications(this, currentUser.id)
supportActionBar?.title = null
initAdapters()
@ -402,7 +401,7 @@ internal class MessageDetailsActivity :
networkSnackBarUtil.hideAllSnackBars()
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.user,
mUserManager.requireCurrentLegacyUser(),
this,
{ onConnectivityCheckRetry() },
anchorViewId = R.id.messageDetailsActionsView,
@ -833,13 +832,12 @@ internal class MessageDetailsActivity :
messageAction,
message.subject
)
val userUsedSpace = SecureSharedPreferences
.getPrefsForUser(this@MessageDetailsActivity, mUserManager.requireCurrentUserId())
.getLong(Constants.Prefs.PREF_USED_SPACE, 0)
val userMaxSpace = if (mUserManager.user.maxSpace == 0L) {
val user = mUserManager.requireCurrentLegacyUser()
val userUsedSpace = user.usedSpace
val userMaxSpace = if (user.maxSpace == 0L) {
Long.MAX_VALUE
} else {
mUserManager.user.maxSpace
user.maxSpace
}
val percentageUsed = userUsedSpace * 100 / userMaxSpace
if (percentageUsed >= 100) {

View File

@ -311,7 +311,7 @@ internal class MessageDetailsViewModel @Inject constructor(
content: String,
mBigContentHolder: BigContentHolder
) {
val user: User = userManager.user
val user: User = userManager.requireCurrentLegacyUser()
viewModelScope.launch {
val intent = messageDetailsRepository.prepareEditMessageIntent(
messageAction,

View File

@ -78,7 +78,7 @@ class AccountManagerActivity : BaseActivity() {
.onEach { (sortedAccounts, primaryUserId) ->
val accounts = sortedAccounts.map { account ->
val id = Id(account.userId.id)
val user = userManager.getLegacyUserOrNull(id)
val user = userManager.getUserOrNull(id)
account.toUiModel(account.isReady(), account.userId == primaryUserId, user)
}
accountsAdapter.items = accounts + DrawerUserModel.AccFooter
@ -105,7 +105,7 @@ class AccountManagerActivity : BaseActivity() {
val next = userManager.getUser(nextLoggedInUserId)
getString(R.string.logout) to getString(R.string.logout_question_next_account, next.name.s)
} else {
val current = checkNotNull(userManager.getCurrentUser())
val current = checkNotNull(userManager.currentUser)
getString(R.string.log_out, current.name.s) to getString(R.string.logout_question)
}

View File

@ -83,7 +83,7 @@ public class AttachmentStorageActivity extends BaseActivity {
mStorageTextValue.setText(String.format(getString(R.string.attachment_storage_value_current), value));
User user = mUserManager.getUser();
User user = mUserManager.getCurrentLegacyUser();
boolean attachmentStorageChanged = mAttachmentStorageCurrentValue != user.getMaxAttachmentStorage();
if (attachmentStorageChanged) {
user.setMaxAttachmentStorage(mAttachmentStorageCurrentValue);

View File

@ -153,7 +153,7 @@ abstract class BaseSettingsActivity : BaseConnectivityActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
legacyUser = userManager.requireCurrentLegacyUserBlocking()
legacyUser = userManager.requireCurrentLegacyUser()
user = legacyUser.toNewUser()
val userId = user.id
@ -186,7 +186,7 @@ abstract class BaseSettingsActivity : BaseConnectivityActivity() {
override fun onResume() {
super.onResume()
legacyUser = userManager.requireCurrentLegacyUserBlocking()
legacyUser = userManager.requireCurrentLegacyUser()
user = legacyUser.toNewUser()
settingsAdapter.notifyDataSetChanged()
viewModel.checkConnectivity()
@ -248,7 +248,7 @@ abstract class BaseSettingsActivity : BaseConnectivityActivity() {
}
private fun selectItem(settingsId: String) {
legacyUser = userManager.requireCurrentLegacyUserBlocking()
legacyUser = userManager.requireCurrentLegacyUser()
user = legacyUser.toNewUser()
when (valueOf(settingsId.toUpperCase(Locale.ENGLISH))) {
ACCOUNT -> {
@ -530,7 +530,7 @@ abstract class BaseSettingsActivity : BaseConnectivityActivity() {
if (connectivity != Constants.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.user,
mUserManager.requireCurrentLegacyUser(),
this,
{ onConnectivityCheckRetry() },
isOffline = connectivity == Constants.ConnectionState.NO_INTERNET

View File

@ -172,7 +172,7 @@ internal class NotificationSettingsActivity : BaseActivity(), ViewStateActivity
currentAction = notificationOptions.indexOf(idOptionsMap[checkedId])
toggleRingtoneContainerVisibility()
val user = mUserManager.user
val user = mUserManager.requireCurrentLegacyUser()
val notificationSettingsChanged = currentAction != user.notificationSetting
if (notificationSettingsChanged) {
user.notificationSetting = currentAction

View File

@ -75,7 +75,7 @@ internal class NotificationSettingsViewModel(
val ringtoneSettings = ViewStateStore<RingtoneSettingsUiModel>().lock
/** Lazy instance of [User] from [UserManager] */
private val user by lazy { userManager.user }
private val user by lazy { userManager.requireCurrentLegacyUser() }
init {
sendRingtoneSettings()

View File

@ -65,7 +65,7 @@ class NetworkConfigurator @Inject constructor(
fun tryRetryWithDoh() {
if (connectivityManager.isInternetConnectionPossible()) {
val isThirdPartyConnectionsEnabled = userManager.getCurrentLegacyUserBlocking()?.allowSecureConnectionsViaThirdParties
val isThirdPartyConnectionsEnabled = userManager.currentLegacyUser?.allowSecureConnectionsViaThirdParties
if (isThirdPartyConnectionsEnabled == true) {
Timber.i("Third party connections enabled, attempting DoH...")
refreshDomainsAsync()
@ -75,7 +75,7 @@ class NetworkConfigurator @Inject constructor(
private suspend fun queryDomains() {
val freshAlternativeUrls = mutableListOf<String>()
val user = userManager.user
val user = userManager.requireCurrentLegacyUser()
if (!user.allowSecureConnectionsViaThirdParties) {
networkSwitcher.reconfigureProxy(null) // force switch to old proxy
user.usingDefaultApi = true
@ -132,9 +132,9 @@ class NetworkConfigurator @Inject constructor(
private fun findWorkingDomain(proxies: Proxies, timestamp: Long) {
val proxyListReference = proxies.proxyList.proxies
scope.launch {
val user = userManager.requireCurrentLegacyUser()
// double-check if normal API call works before resorting to use alternative routing url
if (userManager.user.usingDefaultApi) {
if (user.usingDefaultApi) {
val success = withTimeoutOrNull(DOH_PROVIDER_TIMEOUT) {
val result = try {
networkSwitcher.tryRequest { service ->
@ -174,7 +174,7 @@ class NetworkConfigurator @Inject constructor(
proxies.saveCurrentWorkingProxyDomain(proxies.getCurrentActiveProxy().baseUrl)
proxies.save()
isRunning = false
userManager.user.usingDefaultApi = false
user.usingDefaultApi = false
callback?.startAutoRetry()
callback?.stopDohSignal()
return@launch
@ -184,7 +184,7 @@ class NetworkConfigurator @Inject constructor(
}
callback?.stopAutoRetry()
networkSwitcher.reconfigureProxy(null)
userManager.user.usingDefaultApi = true
user.usingDefaultApi = true
isRunning = false
callback?.stopDohSignal()
}

View File

@ -80,7 +80,7 @@ abstract class BaseRequestInterceptor(
}
private fun check24hExpired(): Boolean {
val user = userManager.getCurrentLegacyUserBlocking()
val user = userManager.currentLegacyUser
val prefs = ProtonMailApplication.getApplication().defaultSharedPreferences
val proxies = Proxies.getInstance(null, prefs)
if (user != null && user.allowSecureConnectionsViaThirdParties && !user.usingDefaultApi) {

View File

@ -143,10 +143,6 @@ public class User {
public static Either<LoadUser.Error, User> load(Id userId, Context context, UserManager userManager) {
final SharedPreferences securePrefs = SecureSharedPreferences.Companion.getPrefsForUser(context, userId);
if (securePrefs.getString(PREF_USER_NAME, null) == null) {
return new Left(LoadUser.Error.NoPreferencesStored.INSTANCE);
}
User user;
try {

View File

@ -59,7 +59,7 @@ public class EventUpdaterService extends ProtonJobIntentService {
protected void onHandleWork(@NonNull Intent intent) {
User user;
try {
user = mUserManager.getCurrentLegacyUserBlocking();
user = mUserManager.getCurrentLegacyUser();
} catch (IllegalStateException e) {
user = null;
}

View File

@ -43,7 +43,6 @@ import ch.protonmail.android.bl.HtmlProcessor
import ch.protonmail.android.compose.send.SendMessage
import ch.protonmail.android.contacts.PostResult
import ch.protonmail.android.core.Constants
import ch.protonmail.android.core.ProtonMailApplication
import ch.protonmail.android.core.UserManager
import ch.protonmail.android.data.local.model.*
import ch.protonmail.android.domain.entity.Id
@ -70,7 +69,6 @@ import io.reactivex.Single
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import me.proton.core.accountmanager.domain.AccountManager
@ -222,7 +220,11 @@ class ComposeMessageViewModel @Inject constructor(
internal var autoSaveJob: Job? = null
// endregion
private val loggedInUserIds = if (userManager.user.combinedContacts) {
private val user by lazy { userManager.requireCurrentLegacyUser() }
private val userId by lazy { userManager.requireCurrentUserId() }
private val loggedInUserIds = if (user.combinedContacts) {
accountManager.allLoggedInBlocking()
} else {
listOf(userManager.currentUserId)
@ -232,10 +234,10 @@ class ComposeMessageViewModel @Inject constructor(
fun init(processor: HtmlProcessor) {
htmlProcessor = processor
composeMessageRepository.lazyManager.reset()
composeMessageRepository.reloadDependenciesForUser(userManager.requireCurrentUserId())
composeMessageRepository.reloadDependenciesForUser(userId)
getSenderEmailAddresses()
// if the user is free user, then we do not fetch contact groups and announce the setup is complete
if (!userManager.user.isPaidUser) {
if (!user.isPaidUser) {
_setupCompleteValue = true
sendingInProcess = false
_setupComplete.postValue(Event(true))
@ -295,7 +297,7 @@ class ComposeMessageViewModel @Inject constructor(
handleContactGroupsResult()
return
}
composeMessageRepository.getContactGroupsFromDB(userId, userManager.user.combinedContacts)
composeMessageRepository.getContactGroupsFromDB(userId, user.combinedContacts)
.flatMap {
for (group in it) {
val emails = composeMessageRepository.getContactGroupEmailsSync(group.ID)
@ -518,7 +520,6 @@ class ComposeMessageViewModel @Inject constructor(
messageDetailsRepository.saveMessage(message)
private fun getSenderEmailAddresses(userEmailAlias: String? = null) {
val user = userManager.user
val senderAddresses = user.senderEmailAddresses
if (senderAddresses.isEmpty()) {
senderAddresses.add(user.defaultAddressEmail)
@ -531,25 +532,24 @@ class ComposeMessageViewModel @Inject constructor(
_senderAddresses = senderAddresses
}
fun getPositionByAddressId(): Int = userManager.user.getPositionByAddressId(_messageDataResult.addressId)
fun getPositionByAddressId(): Int = user.getPositionByAddressId(_messageDataResult.addressId)
fun isPaidUser(): Boolean = userManager.user.isPaidUser
fun isPaidUser(): Boolean = user.isPaidUser
fun getUserAddressByIdFromOnlySendAddresses(): Int = userManager.user.addressByIdFromOnlySendAddresses
fun getUserAddressByIdFromOnlySendAddresses(): Int = user.addressByIdFromOnlySendAddresses
fun setSenderAddressIdByEmail(email: String) {
// sanitize alias address so it points to original address
val nonAliasAddress = "${email.substringBefore("+", email.substringBefore("@"))}@${email.substringAfter("@")}"
_messageDataResult = MessageBuilderData.Builder()
.fromOld(_messageDataResult)
.addressId(userManager.user.getSenderAddressIdByEmail(nonAliasAddress))
.addressId(user.getSenderAddressIdByEmail(nonAliasAddress))
.build()
}
fun getAddressById(): Address = userManager.user.getAddressById(_messageDataResult.addressId)
fun getAddressById(): Address = user.getAddressById(_messageDataResult.addressId)
fun getNewSignature(): String {
val user = userManager.user
return if (user.isShowSignature) {
user.getSignatureForAddress(_messageDataResult.addressId)
} else ""
@ -765,7 +765,6 @@ class ComposeMessageViewModel @Inject constructor(
}
fun initSignatures(): StringBuilder {
val user = userManager.user
var signature = ""
var mobileSignature = ""
val signatureBuilder = StringBuilder()
@ -999,7 +998,6 @@ class ComposeMessageViewModel @Inject constructor(
formattedDateTimeString: String
): MessageBodySetup {
val messageBodySetup = MessageBodySetup()
val user = userManager.user
val builder = StringBuilder()
if (setComposerContent) {
var signatureBuilder = StringBuilder()
@ -1224,7 +1222,7 @@ class ComposeMessageViewModel @Inject constructor(
fun getSignatureByEmailAddress(email: String): String {
val nonAliasAddress = "${email.substringBefore("+", email.substringBefore("@"))}@${email.substringAfter("@")}"
return userManager.user.addresses.find { it.email == nonAliasAddress }?.signature ?: ""
return user.addresses.find { it.email == nonAliasAddress }?.signature ?: ""
}
@SuppressLint("CheckResult")

View File

@ -185,7 +185,7 @@ class ContactsActivity :
if (connectivity != ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.user,
mUserManager.requireCurrentLegacyUser(),
this,
{ onConnectivityCheckRetry() },
isOffline = connectivity == ConnectionState.NO_INTERNET

View File

@ -43,7 +43,7 @@ class ContactsViewModel @Inject constructor(
val fetchContactsResult: LiveData<Boolean> =
fetchContactsTrigger.switchMap { fetchContactsData() }
fun isPaidUser(): Boolean = userManager.user.isPaidUser
fun isPaidUser(): Boolean = userManager.requireCurrentLegacyUser().isPaidUser
fun fetchContacts() {
Timber.v("fetchContacts")

View File

@ -230,7 +230,7 @@ public class ContactDetailsActivity extends BaseActivity implements AppBarLayout
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
mUser = mUserManager.getUser();
mUser = mUserManager.requireCurrentLegacyUser();
Bundle extras = getIntent().getExtras();
inflater = LayoutInflater.from(this);

View File

@ -788,7 +788,7 @@ public class EditContactDetailsActivity extends BaseConnectivityActivity {
if (connectivity != Constants.ConnectionState.CONNECTED) {
networkSnackBarUtil.getNoConnectionSnackBar(
mSnackLayout,
mUserManager.getUser(),
mUserManager.getCurrentLegacyUser(),
this,
null,
null,

View File

@ -120,7 +120,7 @@ class ContactGroupEditCreateViewModel @Inject constructor(private val userManage
}
fun save(name: String) {
val paidUser = userManager.user.isPaidUser
val paidUser = userManager.requireCurrentLegacyUser().isPaidUser
if (!paidUser) {
_contactGroupUpdateResult.postValue(Event(PostResult(status = Status.UNAUTHORIZED)))
return

View File

@ -118,5 +118,5 @@ class ContactGroupsViewModel @Inject constructor(
}
}
fun isPaidUser(): Boolean = userManager.user.isPaidUser
fun isPaidUser(): Boolean = userManager.requireCurrentLegacyUser().isPaidUser
}

View File

@ -24,24 +24,28 @@ import ch.protonmail.android.R
import ch.protonmail.android.api.local.SnoozeSettings
import ch.protonmail.android.api.models.MailSettings
import ch.protonmail.android.api.models.User
import ch.protonmail.android.di.AppCoroutineScope
import ch.protonmail.android.di.BackupSharedPreferences
import ch.protonmail.android.di.DefaultSharedPreferences
import ch.protonmail.android.domain.entity.Id
import ch.protonmail.android.domain.entity.user.Plan
import ch.protonmail.android.domain.util.orThrow
import ch.protonmail.android.domain.util.suspendRunCatching
import ch.protonmail.android.feature.account.allLoggedIn
import ch.protonmail.android.feature.account.primaryId
import ch.protonmail.android.feature.account.primaryLegacyUser
import ch.protonmail.android.feature.account.primaryUser
import ch.protonmail.android.feature.account.primaryUserId
import ch.protonmail.android.prefs.SecureSharedPreferences
import ch.protonmail.android.usecase.LoadLegacyUser
import ch.protonmail.android.usecase.LoadUser
import ch.protonmail.android.utils.crypto.OpenPGP
import ch.protonmail.android.utils.extensions.app
import ch.protonmail.android.utils.extensions.obfuscateUsername
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import me.proton.core.accountmanager.domain.AccountManager
import me.proton.core.crypto.common.keystore.KeyStoreCrypto
import me.proton.core.domain.entity.UserId
import me.proton.core.user.domain.UserManager
import me.proton.core.util.android.sharedpreferences.clearAll
import me.proton.core.util.android.sharedpreferences.get
@ -60,7 +64,6 @@ const val PREF_PIN = "mailbox_pin"
const val PREF_CURRENT_USER_ID = "prefs.current.user.id"
const val PREF_USERNAME = "username"
private const val PREF_KEY_SALT = "key_salt"
private const val PREF_PIN_INCORRECT_ATTEMPTS = "mailbox_pin_incorrect_attempts"
private const val PREF_IS_FIRST_MAILBOX_LOAD_AFTER_LOGIN = "is_first_mailbox_load_after_login"
const val PREF_SHOW_STORAGE_LIMIT_WARNING = "show_storage_limit_warning"
@ -73,6 +76,7 @@ private const val PREF_ENGAGEMENT_SHOWN = "engagement_shown"
/**
* UserManager handles behavior of the current primary account, as well as some multi-account behaviors
*/
@Deprecated("Now replaced by Core UserManager/AccountManager.")
@Singleton
class UserManager @Inject constructor(
private val context: Context,
@ -89,10 +93,71 @@ class UserManager @Inject constructor(
)
val openPgp: OpenPGP,
private val secureSharedPreferencesFactory: SecureSharedPreferences.Factory,
private val dispatchers: DispatcherProvider
private val dispatchers: DispatcherProvider,
@AppCoroutineScope private val scope: CoroutineScope
) {
private val app: ProtonMailApplication = context.app
var primaryUserId: StateFlow<UserId?>
var primaryId: StateFlow<Id?>
var primaryLegacyUser: StateFlow<User?>
var primaryUser: StateFlow<NewUser?>
init {
// Workaround to make sure we have fresh value and get them from main thread without impacting performances.
runBlocking {
primaryUserId = coreAccountManager.primaryUserId(scope)
primaryId = coreAccountManager.primaryId(scope)
primaryLegacyUser = coreAccountManager.primaryLegacyUser(scope) { getLegacyUser(it) }
primaryUser = coreAccountManager.primaryUser(scope) { getUser(it) }
}
}
// region Current User/NewUser.
val currentUserId: Id?
get() = primaryId.value
val currentLegacyUser: User?
get() = primaryLegacyUser.value
val currentUser: NewUser?
get() = primaryUser.value
fun requireCurrentUserId(): Id = checkNotNull(currentUserId)
fun requireCurrentLegacyUser(): User = checkNotNull(currentLegacyUser)
fun requireCurrentUser(): NewUser = checkNotNull(currentUser)
suspend fun getPreviousCurrentUserId(): Id? = coreAccountManager.getPreviousPrimaryUserId()?.let { Id(it.id) }
// endregion
// region User/NewUser by Id
suspend fun getUserOrNull(userId: Id): User? = withContext(dispatchers.Io) {
runCatching { getLegacyUser(userId) }.getOrNull()
}
suspend fun getLegacyUser(userId: Id): User = withContext(dispatchers.Io) {
loadLegacyUser(userId).orThrow()
}
suspend fun getUser(userId: Id): NewUser = withContext(dispatchers.Io) {
loadUser(userId).orThrow()
}
fun getLegacyUserBlocking(userId: Id) = runBlocking {
getLegacyUser(userId)
}
fun getUserBlocking(userId: Id): NewUser = runBlocking {
getUser(userId)
}
// endregion
suspend fun getCurrentUserMailSettings(): MailSettings? =
currentUserId?.let { getMailSettings(it) }
@ -123,9 +188,6 @@ class UserManager @Inject constructor(
val isEngagementShown: Boolean
get() = backupPrefs.getBoolean(PREF_ENGAGEMENT_SHOWN, false)
val currentUserId: Id?
get() = runBlocking { coreAccountManager.getPrimaryUserId().firstOrNull()?.let { Id(it.id) } }
private val currentUserPreferences
get() = currentUserId?.let(::preferencesFor)
@ -140,76 +202,9 @@ class UserManager @Inject constructor(
return secureSharedPreferences.getInt(PREF_PIN_INCORRECT_ATTEMPTS, 0)
}
suspend fun getPreviousCurrentUserId(): Id? = coreAccountManager.getPreviousPrimaryUserId()?.let { Id(it.id) }
@Deprecated("Use suspend function", ReplaceWith("getPreviousCurrentUserId()"))
fun getPreviousCurrentUserIdBlocking(): Id? = runBlocking { getPreviousCurrentUserId() }
fun requireCurrentUserId(): Id =
checkNotNull(currentUserId)
suspend fun getCurrentUser(): NewUser? =
currentUserId?.let {
runCatching { getUser(it) }
.getOrElse {
Timber.d("Cannot load user", it)
null
}
}
suspend fun requireCurrentUser(): NewUser =
getUser(requireCurrentUserId())
@Deprecated(
"Should not be used, necessary only for old and Java classes",
ReplaceWith("getCurrentUser()")
)
fun getCurrentUserBlocking(): NewUser? =
runBlocking { getCurrentUser() }
@Deprecated(
"Should not be used, necessary only for old and Java classes",
ReplaceWith("requireCurrentUser()")
)
fun requireCurrentUserBlocking(): NewUser =
runBlocking { getUser(requireCurrentUserId()) }
suspend fun getCurrentLegacyUser(): User? =
currentUserId?.let {
runCatching { getLegacyUser(it) }
.getOrElse {
Timber.d("Cannot load user", it)
null
}
}
suspend fun requireCurrentLegacyUser(): User =
getLegacyUser(requireCurrentUserId())
@Deprecated(
"Should not be used, necessary only for old and Java classes",
ReplaceWith("getCurrentLegacyUser()")
)
fun getCurrentLegacyUserBlocking(): User? =
runBlocking { getCurrentLegacyUser() }
@Deprecated(
"Should not be used, necessary only for old and Java classes",
ReplaceWith("requireCurrentOldUser()")
)
fun requireCurrentLegacyUserBlocking(): User =
runBlocking { getLegacyUser(requireCurrentUserId()) }
/**
* Use this method to get settings for currently active User.
*/
@get:Deprecated("Use ''getCurrentLegacyUser'", ReplaceWith("getCurrentLegacyUser()"))
val user: User
get() = requireNotNull(getCurrentLegacyUserBlocking())
@Deprecated("Use 'currentUser' variant", ReplaceWith("isCurrentUserBackgroundSyncEnabled()"))
val isBackgroundSyncEnabled: Boolean
get() = user.isBackgroundSync
get() = currentLegacyUser?.isBackgroundSync ?: false
fun isCurrentUserSnoozeScheduledEnabled(): Boolean {
val userId = requireNotNull(currentUserId)
@ -266,85 +261,6 @@ class UserManager @Inject constructor(
fun getMailboxPin(): String? =
app.secureSharedPreferences.getString(PREF_PIN, "")
suspend fun saveKeySalt(userId: Id, keysSalt: String?) {
withContext(dispatchers.Io) {
val secureSharedPreferences = preferencesFor(userId)
secureSharedPreferences[PREF_KEY_SALT] = keysSalt
}
}
@Deprecated(
"Should not be used, necessary only for old and Java classes",
ReplaceWith("saveKeySalt(userId, keySalt)")
)
fun saveKeySaltBlocking(userId: Id, keysSalt: String?) {
runBlocking {
saveKeySalt(userId, keysSalt)
}
}
suspend fun saveTempKeySalt(keysSalt: String?) {
saveKeySalt(TEMP_USER_ID, keysSalt)
}
@Deprecated(
"Should not be used, necessary only for old and Java classes",
ReplaceWith("saveTempKeySalt(keySalt)")
)
@JvmOverloads
fun saveTempKeySaltBlocking(keysSalt: String?) {
runBlocking {
saveKeySalt(TEMP_USER_ID, keysSalt)
}
}
@Synchronized
suspend fun getUser(userId: Id): NewUser =
loadUser(userId).orThrow()
@Deprecated("Suspended function should be used instead", ReplaceWith("getUser(userId)"))
fun getUserBlocking(userId: Id): NewUser =
runBlocking { getUser(userId) }
/**
* Note, returned [User] might have empty values if user was not saved before
*/
@Synchronized
suspend fun getLegacyUser(userId: Id): User =
loadLegacyUser(userId).orThrow()
@Synchronized
suspend fun getLegacyUserOrNull(userId: Id): User? =
loadLegacyUser(userId).orNull()
@Deprecated(
"Should not be used, necessary only for old and Java classes",
ReplaceWith("getLegacyUser(userId)")
)
fun getLegacyUserBlocking(userId: Id) = runBlocking {
getLegacyUser(userId)
}
/**
* @return `true` if another account can be connected
* `false` if there are logged in more than one Free account
* @see NewUser.plans
* @see Plan.Mail.Free
*/
suspend fun canConnectAnotherAccount(): Boolean {
val freeLoggedInUserCount = coreAccountManager.allLoggedIn().count {
val user = suspendRunCatching { getUser(it) }
.getOrNull()
?: return@count false
Plan.Mail.Free in user.plans
}
return freeLoggedInUserCount <= 1
}
@Deprecated("Use suspend function", ReplaceWith("canConnectAnotherAccount"))
fun canConnectAnotherAccountBlocking(): Boolean =
runBlocking { canConnectAnotherAccount() }
fun canShowStorageLimitWarning(): Boolean =
withCurrentUserPreferences { it[PREF_SHOW_STORAGE_LIMIT_WARNING] } ?: true
@ -449,7 +365,7 @@ class UserManager @Inject constructor(
if (organization != null) {
planName = organization.planName
paidUser = user.isPaidUser && organization.planName.isNullOrEmpty().not()
paidUser = currentLegacyUser?.isPaidUser == true && organization.planName.isNullOrEmpty().not()
}
if (!paidUser) {
return maxLabelsAllowed
@ -490,9 +406,4 @@ class UserManager @Inject constructor(
}
}
}
private companion object {
val TEMP_USER_ID = Id("temp")
}
}

View File

@ -24,7 +24,6 @@ import ch.protonmail.android.domain.entity.Id
import ch.protonmail.android.domain.entity.PgpField
import ch.protonmail.android.domain.entity.user.AddressKey
import ch.protonmail.android.domain.entity.user.AddressKeys
import ch.protonmail.android.mapper.bridge.UserBridgeMapper
import ch.protonmail.android.utils.crypto.BinaryDecryptionResult
import ch.protonmail.android.utils.crypto.EOToken
import ch.protonmail.android.utils.crypto.MimeDecryptor
@ -38,7 +37,6 @@ import com.proton.gopenpgp.crypto.PlainMessage
import com.proton.gopenpgp.crypto.SessionKey
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import kotlinx.coroutines.runBlocking
import timber.log.Timber
import com.proton.gopenpgp.crypto.Crypto as GoOpenPgpCrypto
@ -46,9 +44,8 @@ class AddressCrypto @AssistedInject constructor(
val userManager: UserManager,
openPgp: OpenPGP,
@Assisted userId: Id,
@Assisted private val addressId: Id,
userMapper: UserBridgeMapper = UserBridgeMapper.buildDefault()
) : Crypto<AddressKey>(userManager, openPgp, userId, userMapper) {
@Assisted private val addressId: Id
) : Crypto<AddressKey>(userManager, openPgp, userId) {
@AssistedInject.Factory
interface Factory {
@ -93,8 +90,7 @@ class AddressCrypto @AssistedInject constructor(
"primary = ${key.isPrimary}, " +
"has activation = ${key.activation != null}"
val user = runBlocking { userManager.getCurrentUserBlocking() }
val armoredPrivateKey: String? = user?.keys?.primaryKey?.privateKey?.string
val armoredPrivateKey: String? = user.keys.primaryKey?.privateKey?.string
armoredPrivateKey?.let {
val decryptedToken = openPgp.decryptMessage(token.string, armoredPrivateKey, mailboxPassword)
val validSignature = verifySignature(it, decryptedToken, signature.string, errorMessage)

View File

@ -26,12 +26,10 @@ import ch.protonmail.android.domain.entity.user.AddressKeys
import ch.protonmail.android.domain.entity.user.UserKey
import ch.protonmail.android.domain.entity.user.UserKeys
import ch.protonmail.android.feature.user.getMailboxPasswordBlocking
import ch.protonmail.android.mapper.bridge.UserBridgeMapper
import ch.protonmail.android.utils.crypto.OpenPGP
import ch.protonmail.android.utils.crypto.TextDecryptionResult
import com.proton.gopenpgp.armor.Armor
import me.proton.core.util.kotlin.EMPTY_STRING
import me.proton.core.util.kotlin.invoke
import timber.log.Timber
import com.proton.gopenpgp.crypto.Crypto as GoOpenPgpCrypto
@ -47,12 +45,11 @@ import com.proton.gopenpgp.crypto.Crypto as GoOpenPgpCrypto
abstract class Crypto<K>(
private val userManager: UserManager,
protected val openPgp: OpenPGP,
private val userId: Id,
private val userMapper: UserBridgeMapper = UserBridgeMapper.buildDefault()
private val userId: Id
) {
protected val user by lazy {
userMapper { userManager.getUserBlocking(userId) }
userManager.getUserBlocking(userId)
}
protected val userKeys

View File

@ -23,7 +23,6 @@ import ch.protonmail.android.domain.entity.Id
import ch.protonmail.android.domain.entity.PgpField
import ch.protonmail.android.domain.entity.user.AddressKey
import ch.protonmail.android.domain.entity.user.UserKey
import ch.protonmail.android.mapper.bridge.UserBridgeMapper
import ch.protonmail.android.utils.crypto.KeyInformation
import ch.protonmail.android.utils.crypto.OpenPGP
import ch.protonmail.android.utils.crypto.TextDecryptionResult
@ -33,9 +32,8 @@ import java.util.Arrays
class UserCrypto(
userManager: UserManager,
openPgp: OpenPGP,
userId: Id,
userMapper: UserBridgeMapper = UserBridgeMapper.buildDefault()
) : Crypto<UserKey>(userManager, openPgp, userId, userMapper) {
userId: Id
) : Crypto<UserKey>(userManager, openPgp, userId) {
override val currentKeys: Collection<UserKey>
get() = userKeys.keys

View File

@ -313,7 +313,7 @@ data class Message @JvmOverloads constructor(
}
val app = ProtonMailApplication.getApplication()
val userManager = app.userManager
val user = userManager.user
val user = userManager.currentLegacyUser
return user!!.addresses!!.any { it.email.equals(senderEmail, ignoreCase = true) }
}

View File

@ -199,7 +199,7 @@ object ApplicationModule {
): ProtonRetrofitBuilder {
// userManager.user.allowSecureConnectionsViaThirdParties)
val user = userManager.getCurrentLegacyUserBlocking()
val user = userManager.currentLegacyUser
val dnsOverHttpsHost =
if (user != null && !user.usingDefaultApi)
Proxies.getInstance(null, prefs).getCurrentWorkingProxyDomain()

View File

@ -19,12 +19,19 @@
package ch.protonmail.android.feature.account
import ch.protonmail.android.api.models.User
import ch.protonmail.android.domain.entity.Id
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.runBlocking
import me.proton.core.account.domain.entity.AccountState
import me.proton.core.accountmanager.domain.AccountManager
import me.proton.core.accountmanager.domain.getAccounts
import me.proton.core.domain.entity.UserId
import ch.protonmail.android.domain.entity.user.User as NewUser
@Deprecated("Replaced by Core AccountManager", ReplaceWith("Core AccountManager"))
fun AccountManager.allLoggedInBlocking() = runBlocking { allLoggedIn() }
@ -36,3 +43,15 @@ suspend fun AccountManager.allLoggedIn() =
@Deprecated("Replaced by Core AccountManager", ReplaceWith("Core AccountManager"))
suspend fun AccountManager.allSaved() =
getAccounts(AccountState.Disabled).firstOrNull()?.map { Id(it.userId.id) }.orEmpty().toSet()
suspend fun AccountManager.primaryUserId(scope: CoroutineScope): StateFlow<UserId?> =
getPrimaryUserId().stateIn(scope)
suspend fun AccountManager.primaryId(scope: CoroutineScope): StateFlow<Id?> =
primaryUserId(scope).mapLatest { it?.let { Id(it.id) } }.stateIn(scope)
suspend fun AccountManager.primaryLegacyUser(scope: CoroutineScope, getUser: suspend (Id) -> User): StateFlow<User?> =
primaryId(scope).mapLatest { it?.let { getUser(it) } }.stateIn(scope)
suspend fun AccountManager.primaryUser(scope: CoroutineScope, getNewUser: suspend (Id) -> NewUser): StateFlow<NewUser?> =
primaryId(scope).mapLatest { it?.let { getNewUser(it) } }.stateIn(scope)

View File

@ -45,13 +45,13 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.transformLatest
import kotlinx.coroutines.launch
import me.proton.core.account.domain.entity.Account
import me.proton.core.account.domain.entity.AccountType
import me.proton.core.account.domain.entity.isDisabled
import me.proton.core.account.domain.entity.isReady
import me.proton.core.accountmanager.domain.AccountManager
import me.proton.core.accountmanager.domain.getPrimaryAccount
import me.proton.core.accountmanager.presentation.disableInitialNotReadyAccounts
import me.proton.core.accountmanager.presentation.observe
import me.proton.core.accountmanager.presentation.onAccountCreateAddressFailed
@ -82,7 +82,7 @@ class AccountViewModel @ViewModelInject constructor(
object Processing : State()
object LoginClosed : State()
object AccountNeeded : State()
data class AccountList(val accounts: List<Account>) : State()
object PrimaryExist : State()
}
val state = _state.asStateFlow()
@ -94,10 +94,10 @@ class AccountViewModel @ViewModelInject constructor(
with(authOrchestrator) {
onLoginResult { result -> if (result == null) _state.tryEmit(State.LoginClosed) }
accountManager.observe(context.lifecycle, minActiveState = Lifecycle.State.CREATED)
.onSessionHumanVerificationNeeded { startHumanVerificationWorkflow(it) }
.onSessionSecondFactorNeeded { startSecondFactorWorkflow(it) }
.onAccountTwoPassModeNeeded { startTwoPassModeWorkflow(it) }
.onAccountCreateAddressNeeded { startChooseAddressWorkflow(it) }
.onSessionHumanVerificationNeeded { startHumanVerificationWorkflow(it) }
.onAccountTwoPassModeFailed { accountManager.disableAccount(it.userId) }
.onAccountCreateAddressFailed { accountManager.disableAccount(it.userId) }
.onAccountDisabled { onAccountDisabled(it) }
@ -108,30 +108,27 @@ class AccountViewModel @ViewModelInject constructor(
// Raise LoginNeeded on empty account list.
accountManager.getAccounts()
.flowWithLifecycle(context.lifecycle, Lifecycle.State.CREATED)
.onEach { accounts ->
.transformLatest { accounts ->
when {
accounts.isEmpty() || accounts.all { it.isDisabled() } -> {
onAccountNeeded()
_state.tryEmit(State.AccountNeeded)
emit(State.AccountNeeded)
}
accounts.any { it.isReady() } -> {
_state.tryEmit(State.AccountList(accounts))
// Wait getPrimaryUserId != null.
getPrimaryUserId().first { it != null }
emit(State.PrimaryExist)
}
}
}.launchIn(viewModelScope)
}
.onEach { state -> _state.tryEmit(state) }
.launchIn(viewModelScope)
}
fun getPrimaryUserId() = accountManager.getPrimaryUserId()
fun getPrimaryAccount() = accountManager.getPrimaryAccount()
fun getAccount(userId: UserId) = accountManager.getAccount(userId)
suspend fun getAccountOrNull(userId: UserId) = getAccount(userId).firstOrNull()
fun getAccounts() = accountManager.getAccounts()
/* Order: Primary account, ready account(s), other account(s). */
fun getSortedAccounts() = accountManager.getAccounts().mapLatest { accounts ->
val currentUser = getPrimaryUserId().firstOrNull()
@ -179,6 +176,15 @@ class AccountViewModel @ViewModelInject constructor(
)
}.filter { it.previous != null && it.current != it.previous }
// region Primary User Id
// Currently, Old UserManager is the source of truth for current primary user id.
fun getPrimaryUserId() = oldUserManager.primaryUserId
fun getPrimaryUserIdValue() = oldUserManager.primaryUserId.value
// endregion
// region Deprecated
@Deprecated(

View File

@ -62,7 +62,7 @@ public class ResignContactJob extends ProtonMailEndlessJob {
ContactDao contactDao = ContactDatabase.Companion
.getInstance(getApplicationContext(), getUserId())
.getDao();
User user = getUserManager().getUser();
User user = getUserManager().getCurrentLegacyUser();
String contactId = getContactId(contactDao, mContactEmail);
if (contactId == null) {
AppUtil.postEventOnUi(new ResignContactEvent(mSendPreference, ContactEvent.ERROR, mDestination));

View File

@ -41,7 +41,7 @@ class UpdateSettingsJob(
@Throws(Throwable::class)
override fun onRun() {
try {
val user = getUserManager().requireCurrentLegacyUserBlocking()
val user = getUserManager().requireCurrentLegacyUser()
val userId = Id(user.id)
if (addressIds != null) {
getUserAddressManager().updateOrderBlocking(userId, addressIds.map { Id(it) })

View File

@ -104,7 +104,7 @@ class ChangePinActivity : BaseActivity(),
}
private fun logout() {
mUserManager.requireCurrentLegacyUserBlocking().apply {
mUserManager.requireCurrentLegacyUser().apply {
isUsePin = false
isUseFingerprint = false
}

View File

@ -60,7 +60,7 @@ class PinSettingsActivity : BaseActivity() {
private val useFingerprintToggle by lazy { useFingerprint.getToggle() }
private val autoLockOtherSettingsContainer by lazy { findViewById<LinearLayout>(R.id.autoLockOtherSettingsContainer) }
private var mPinTimeoutValue: Int = 0
private val user by lazy { mUserManager.user }
private val user by lazy { mUserManager.requireCurrentLegacyUser() }
private val mBiometricManager by lazy {
BiometricManager.from(this@PinSettingsActivity)

View File

@ -77,13 +77,15 @@ class ValidatePinActivity : BaseActivity(),
if (savedInstanceState != null) {
return
}
val user = mUserManager.requireCurrentLegacyUser()
val titleRes = intent.getIntExtra(EXTRA_FRAGMENT_TITLE, 0)
val validatePinFragment = PinFragment.newInstance(titleRes, PinAction.VALIDATE,
null, useFingerprint = mUserManager.user.isUseFingerprint)
supportFragmentManager.beginTransaction()
.add(R.id.fragmentContainer, validatePinFragment, validatePinFragment.fragmentKey).commitAllowingStateLoss()
val validatePinFragment = PinFragment.newInstance(titleRes, PinAction.VALIDATE, null, useFingerprint = user.isUseFingerprint)
supportFragmentManager
.beginTransaction()
.add(R.id.fragmentContainer, validatePinFragment, validatePinFragment.fragmentKey)
.commitAllowingStateLoss()
if (mUserManager.user.isUseFingerprint) {
if (user.isUseFingerprint) {
initBiometricPrompt()
}
}
@ -146,7 +148,7 @@ class ValidatePinActivity : BaseActivity(),
}
override fun onPinSuccess() {
mUserManager.user.setManuallyLocked(false)
mUserManager.requireCurrentLegacyUser().setManuallyLocked(false)
mPinValid = true
setResult(Activity.RESULT_OK, buildIntent())
saveLastInteraction()
@ -190,7 +192,7 @@ class ValidatePinActivity : BaseActivity(),
}
private fun logout() {
mUserManager.requireCurrentLegacyUserBlocking().apply {
mUserManager.requireCurrentLegacyUser().apply {
isUsePin = false
isUseFingerprint = false
}

View File

@ -51,7 +51,5 @@ class LoadUser @Inject constructor(
invoke(userId)
}
sealed class Error : ch.protonmail.android.domain.Error() {
object NoPreferencesStored : Error()
}
sealed class Error : ch.protonmail.android.domain.Error()
}

View File

@ -31,7 +31,7 @@ class GenerateTokenAndSignature @Inject constructor (
private val openPgp: OpenPGP
) {
suspend operator fun invoke(orgKeys: UserKey?): TokenAndSignature {
val user = userManager.getCurrentUserBlocking()
val user = userManager.currentUser
val secret = openPgp.randomToken()
val tokenString = secret.joinToString("") { String.format("%02x", (it.toInt() and 0xff)) }
val binMessage = Crypto.newPlainMessageFromString(tokenString)

View File

@ -46,7 +46,7 @@ public class UserUtils {
String planName = accountTypes.get(0); // free
int maxLabelsAllowed = maxLabelsPerPlanArray.get(0); // free
User user = userManager.getUser();
User user = userManager.getCurrentLegacyUser();
if (user != null && organization != null) {
planName = organization.getPlanName();
paidUser = user.isPaidUser() && !TextUtils.isEmpty(organization.getPlanName());

View File

@ -24,7 +24,6 @@ import android.os.Handler
import android.os.Looper
import ch.protonmail.android.R
import ch.protonmail.android.core.UserManager
import ch.protonmail.android.data.local.model.Message
import ch.protonmail.android.servers.notification.NotificationServer
import ch.protonmail.android.utils.extensions.showToast
import kotlinx.coroutines.withContext
@ -39,7 +38,7 @@ class AndroidUserNotifier @Inject constructor(
) : UserNotifier {
override fun showPersistentError(errorMessage: String, messageSubject: String?) {
val user = userManager.requireCurrentUserBlocking()
val user = userManager.requireCurrentUser()
notificationServer.notifySaveDraftError(user.id, errorMessage, messageSubject, user.name)
}
@ -51,7 +50,7 @@ class AndroidUserNotifier @Inject constructor(
override fun showSendMessageError(errorMessage: String, messageSubject: String?) {
val error = "\"$messageSubject\" - $errorMessage"
val user = userManager.requireCurrentUserBlocking()
val user = userManager.requireCurrentUser()
notificationServer.notifySingleErrorSendingMessage(user.id, user.name, error)
}

View File

@ -123,7 +123,7 @@ public class PMWebViewClient extends WebViewClient {
);
MailTo mt = MailTo.parse(url);
User user = mUserManager.getUser();
User user = mUserManager.getCurrentLegacyUser();
MessageUtils.INSTANCE.addRecipientsToIntent(
intent,
ComposeMessageActivity.EXTRA_TO_RECIPIENTS,

View File

@ -29,7 +29,6 @@ import ch.protonmail.android.core.UserManager
import ch.protonmail.android.domain.entity.Id
import ch.protonmail.android.utils.AppUtil
import ch.protonmail.android.utils.notifier.UserNotifier
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
@ -64,9 +63,7 @@ class BaseRequestInterceptorTest {
private val userManagerMock = mockk<UserManager> {
every { currentUserId } returns testUserId
every { getMailboxPassword(testUserId) } returns "mailbox password".toByteArray()
coEvery { getCurrentLegacyUser() } returns userMock
every { getCurrentLegacyUserBlocking() } returns userMock
every { this@mockk.currentLegacyUser } returns userMock
}
private val sessionManagerMock = mockk<SessionManager>()

View File

@ -63,7 +63,7 @@ class ComposeMessageViewModelTest : ArchTest, CoroutinesTest {
private val composeMessageRepository: ComposeMessageRepository = mockk(relaxed = true)
private val userManager: UserManager = mockk(relaxed = true) {
every { user.senderEmailAddresses } returns mutableListOf()
every { requireCurrentLegacyUser().senderEmailAddresses } returns mutableListOf()
}
private val messageDetailsRepository: MessageDetailsRepository = mockk(relaxed = true) {

View File

@ -22,6 +22,7 @@ package ch.protonmail.android.usecase.fetch
import ch.protonmail.android.api.ProtonMailApiManager
import ch.protonmail.android.api.models.PublicKeyBody
import ch.protonmail.android.api.models.PublicKeyResponse
import ch.protonmail.android.api.models.User
import ch.protonmail.android.core.Constants
import ch.protonmail.android.core.UserManager
import ch.protonmail.android.crypto.UserCrypto
@ -29,7 +30,6 @@ import ch.protonmail.android.data.local.ContactDao
import ch.protonmail.android.data.local.model.ContactEmail
import ch.protonmail.android.data.local.model.FullContactDetailsResponse
import ch.protonmail.android.domain.entity.Id
import ch.protonmail.android.domain.entity.user.User
import ch.protonmail.android.utils.crypto.KeyInformation
import io.mockk.coEvery
import io.mockk.every
@ -44,14 +44,14 @@ class FetchVerificationKeysTest : CoroutinesTest {
private val testUserId = Id("id")
private val testUser = mockk<User> {
every { id } returns testUserId
every { id } returns testUserId.s
every { addresses } returns mockk(relaxed = true)
}
private val api: ProtonMailApiManager = mockk()
private val userManager: UserManager = mockk {
coEvery { requireCurrentUser() } returns testUser
coEvery { this@mockk.requireCurrentLegacyUser() } returns testUser
every { currentUserId } returns testUserId
every { requireCurrentUserId() } returns testUserId
every { openPgp } returns mockk()

View File

@ -51,7 +51,7 @@ class AndroidUserNotifierTest : CoroutinesTest {
private val userManager: UserManager = mockk {
every { currentUserId } returns testUserId
every { requireCurrentUserId() } returns testUserId
every { requireCurrentUserBlocking() } returns mockk {
every { this@mockk.requireCurrentUser() } returns mockk {
every { id } returns testUserId
every { name } returns testUserName
}

View File

@ -106,7 +106,7 @@ class FetchUserInfoWorkerTest {
coEvery { protonMailApiManager.fetchUserInfo() } returns mockUserInfoResponse
coEvery { protonMailApiManager.fetchAddresses() } returns mockAddressesResponse
every { userManager.user } returns mockUser
every { userManager.currentLegacyUser } returns mockUser
val expectedResult = ListenableWorker.Result.success(workDataOf(FETCH_USER_INFO_WORKER_RESULT to false))
@ -134,7 +134,7 @@ class FetchUserInfoWorkerTest {
coEvery { protonMailApiManager.fetchUserInfo() } returns mockUserInfoResponse
coEvery { protonMailApiManager.fetchAddresses() } returns mockAddressesResponse
every { userManager.user } returns mockUser
every { userManager.currentLegacyUser } returns mockUser
val expectedResult = ListenableWorker.Result.success(workDataOf(FETCH_USER_INFO_WORKER_RESULT to true))