refactor: The presentation module does not depend on network* modules.

The following elements have been moved from `presentation` to `network-presentation`:
`ProtonWebViewActivity`, `ProtonWebViewClient`, `Throwable.getUserMessage`.
This commit is contained in:
Mateusz Armatys
2024-07-25 14:29:56 +02:00
parent 379c6f0d9e
commit 4a159b8141
50 changed files with 150 additions and 103 deletions
@@ -32,7 +32,7 @@ import me.proton.core.compose.theme.ProtonTheme
import me.proton.core.domain.entity.UserId
import me.proton.core.presentation.ui.ProtonActivity
import me.proton.core.presentation.utils.errorToast
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.successToast
import javax.inject.Inject
@@ -31,7 +31,7 @@ import me.proton.core.compose.theme.ProtonTheme
import me.proton.core.domain.entity.UserId
import me.proton.core.presentation.ui.ProtonActivity
import me.proton.core.presentation.utils.errorToast
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.openBrowserLink
import me.proton.core.presentation.utils.successToast
+1
View File
@@ -57,6 +57,7 @@ dependencies {
project(Module.humanVerificationPresentation),
project(Module.networkData),
project(Module.networkDomain),
project(Module.networkPresentation),
project(Module.observabilityDomain),
project(Module.paymentDomain),
project(Module.paymentPresentation),
@@ -40,7 +40,7 @@ import me.proton.core.auth.presentation.viewmodel.ChooseAddressViewModel
import me.proton.core.auth.presentation.viewmodel.ChooseAddressViewModel.State
import me.proton.core.domain.entity.UserId
import me.proton.core.observability.domain.metrics.LoginScreenViewTotal
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
@@ -43,7 +43,7 @@ import me.proton.core.domain.entity.UserId
import me.proton.core.presentation.ui.ProtonFragment
import me.proton.core.presentation.utils.SnackbarLength
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.openBrowserLink
import me.proton.core.presentation.utils.viewBinding
@@ -30,7 +30,6 @@ import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
@@ -44,7 +43,7 @@ import me.proton.core.auth.presentation.entity.NextStep
import me.proton.core.auth.presentation.viewmodel.LoginViewModel
import me.proton.core.domain.entity.UserId
import me.proton.core.presentation.utils.addOnBackPressedCallback
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.normToast
import me.proton.core.presentation.utils.onClick
@@ -54,11 +54,11 @@ import me.proton.core.network.data.di.BaseProtonApiUrl
import me.proton.core.network.domain.NetworkPrefs
import me.proton.core.network.domain.client.ExtraHeaderProvider
import me.proton.core.network.domain.session.SessionProvider
import me.proton.core.network.presentation.ui.ProtonWebViewActivity
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.observability.domain.metrics.LoginScreenViewTotal
import me.proton.core.presentation.ui.ProtonWebViewActivity
import me.proton.core.presentation.ui.ProtonWebViewActivity.Companion.ResultContract
import me.proton.core.presentation.ui.ProtonWebViewActivity.Result
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.ui.ProtonWebViewActivity.Companion.ResultContract
import me.proton.core.network.presentation.ui.ProtonWebViewActivity.Result
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
@@ -49,10 +49,10 @@ import me.proton.core.auth.presentation.entity.TwoFAMechanisms
import me.proton.core.auth.presentation.util.setTextWithAnnotatedLink
import me.proton.core.auth.presentation.viewmodel.SecondFactorViewModel
import me.proton.core.domain.entity.UserId
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.observability.domain.metrics.LoginScreenViewTotal
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.errorToast
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
@@ -36,7 +36,7 @@ import me.proton.core.auth.presentation.entity.TwoPassModeInput
import me.proton.core.auth.presentation.entity.TwoPassModeResult
import me.proton.core.auth.presentation.viewmodel.TwoPassModeViewModel
import me.proton.core.domain.entity.UserId
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.onFailure
@@ -41,7 +41,7 @@ import me.proton.core.auth.presentation.viewmodel.signup.ChooseExternalEmailView
import me.proton.core.auth.presentation.viewmodel.signup.ChooseExternalEmailViewModel.State
import me.proton.core.auth.presentation.viewmodel.signup.SignupViewModel
import me.proton.core.observability.domain.metrics.SignupScreenViewTotalV1
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
@@ -41,7 +41,7 @@ import me.proton.core.auth.presentation.viewmodel.signup.ChooseInternalEmailView
import me.proton.core.auth.presentation.viewmodel.signup.ChooseUsernameViewModel
import me.proton.core.auth.presentation.viewmodel.signup.SignupViewModel
import me.proton.core.observability.domain.metrics.SignupScreenViewTotalV1
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
@@ -39,7 +39,7 @@ import me.proton.core.auth.presentation.viewmodel.signup.ChooseUsernameViewModel
import me.proton.core.auth.presentation.viewmodel.signup.ChooseUsernameViewModel.State
import me.proton.core.auth.presentation.viewmodel.signup.SignupViewModel
import me.proton.core.observability.domain.metrics.SignupScreenViewTotalV1
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
@@ -34,7 +34,7 @@ import me.proton.core.auth.presentation.viewmodel.signup.TermsConditionsViewMode
import me.proton.core.network.domain.NetworkPrefs
import me.proton.core.network.domain.client.ExtraHeaderProvider
import me.proton.core.presentation.ui.ProtonDialogFragment
import me.proton.core.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.network.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.viewBinding
import javax.inject.Inject
@@ -32,12 +32,11 @@ import me.proton.core.account.domain.entity.AccountType
import me.proton.core.auth.presentation.R
import me.proton.core.auth.presentation.databinding.FragmentSignupRecoveryBinding
import me.proton.core.auth.presentation.entity.signup.RecoveryMethodType
import me.proton.core.auth.presentation.util.setTextWithAnnotatedLink
import me.proton.core.auth.presentation.viewmodel.signup.RecoveryMethodViewModel
import me.proton.core.auth.presentation.viewmodel.signup.SignupViewModel
import me.proton.core.observability.domain.metrics.SignupScreenViewTotalV1
import me.proton.core.presentation.ui.alert.FragmentDialogResultLauncher
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
@@ -62,7 +62,7 @@ import me.proton.core.plan.presentation.ui.BasePlansFragment.Companion.KEY_PLAN_
import me.proton.core.plan.presentation.ui.hasPlanSignupFragment
import me.proton.core.plan.presentation.ui.removePlansSignup
import me.proton.core.plan.presentation.ui.showPlansSignup
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.telemetry.domain.entity.TelemetryPriority
import me.proton.core.telemetry.presentation.ProductMetricsDelegate
import me.proton.core.telemetry.presentation.UiComponentProductMetricsDelegateOwner
@@ -34,7 +34,7 @@ import me.proton.core.auth.presentation.viewmodel.signup.TermsConditionsViewMode
import me.proton.core.network.domain.NetworkPrefs
import me.proton.core.network.domain.client.ExtraHeaderProvider
import me.proton.core.presentation.ui.ProtonDialogFragment
import me.proton.core.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.network.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.viewBinding
import javax.inject.Inject
@@ -30,12 +30,12 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.parcelize.Parcelize
import me.proton.core.auth.domain.usecase.AccountAvailability
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.observability.domain.ObservabilityContext
import me.proton.core.observability.domain.ObservabilityManager
import me.proton.core.observability.domain.metrics.SignupEmailAvailabilityTotal
import me.proton.core.observability.domain.metrics.SignupFetchDomainsTotal
import me.proton.core.presentation.savedstate.flowState
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.presentation.viewmodel.ProtonViewModel
import me.proton.core.util.kotlin.coroutine.launchWithResultContext
import javax.inject.Inject
@@ -46,7 +46,7 @@ import me.proton.core.network.domain.scopes.MissingScopeListener
import me.proton.core.network.domain.scopes.Scope
import me.proton.core.network.domain.session.SessionId
import me.proton.core.observability.domain.ObservabilityManager
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.test.android.ArchTest
import me.proton.core.test.kotlin.CoroutinesTest
import me.proton.core.test.kotlin.assertIs
@@ -47,7 +47,7 @@ import me.proton.core.observability.domain.metrics.ObservabilityData
import me.proton.core.observability.domain.metrics.SignupLoginTotal
import me.proton.core.observability.domain.metrics.SignupUnlockUserTotalV1
import me.proton.core.observability.domain.metrics.SignupUserCheckTotalV1
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.telemetry.domain.TelemetryManager
import me.proton.core.telemetry.domain.entity.TelemetryEvent
import me.proton.core.test.android.ArchTest
@@ -49,6 +49,7 @@ dependencies {
project(Module.humanVerificationDomain),
project(Module.observabilityDomain),
project(Module.networkDomain),
project(Module.networkPresentation),
project(Module.presentation),
project(Module.userSettingsDomain),
project(Module.telemetryPresentation),
@@ -33,7 +33,7 @@ import me.proton.core.humanverification.presentation.LogTag
import me.proton.core.humanverification.presentation.LogTag.HV_REQUEST_ERROR
import me.proton.core.network.domain.NetworkPrefs
import me.proton.core.network.domain.client.ExtraHeaderProvider
import me.proton.core.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.network.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.util.kotlin.CoreLogger
import me.proton.core.util.kotlin.annotation.ExcludeFromCoverage
import me.proton.core.util.kotlin.takeIfNotBlank
+2
View File
@@ -22,6 +22,7 @@ import studio.forface.easygradle.dsl.android.*
plugins {
protonAndroidLibrary
protonDagger
id("kotlin-parcelize")
}
protonCoverage {
@@ -46,6 +47,7 @@ dependencies {
implementation(
project(Module.accountDomain),
project(Module.domain),
project(Module.networkData),
project(Module.presentation),
activity,
@@ -20,6 +20,10 @@
xmlns:tools="http://schemas.android.com/tools">
<application>
<activity
android:name="me.proton.core.network.presentation.ui.ProtonWebViewActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
<provider
android:name="androidx.startup.InitializationProvider"
@@ -1,4 +1,22 @@
package me.proton.core.presentation.ui
/*
* Copyright (c) 2024 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonCore is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.network.presentation.ui
import android.app.Activity
import android.content.Context
@@ -18,27 +36,28 @@ import kotlinx.parcelize.Parcelize
import me.proton.core.network.data.di.BaseProtonApiUrl
import me.proton.core.network.domain.NetworkPrefs
import me.proton.core.network.domain.client.ExtraHeaderProvider
import me.proton.core.network.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.presentation.databinding.ProtonWebviewActivityBinding
import me.proton.core.presentation.ui.webview.ProtonWebViewClient
import me.proton.core.presentation.ui.ProtonSecureActivity
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import java.io.ByteArrayInputStream
import javax.inject.Inject
@AndroidEntryPoint
class ProtonWebViewActivity : ProtonSecureActivity<ProtonWebviewActivityBinding>(
public class ProtonWebViewActivity : ProtonSecureActivity<ProtonWebviewActivityBinding>(
ProtonWebviewActivityBinding::inflate
) {
@Inject
@BaseProtonApiUrl
lateinit var baseApiUrl: HttpUrl
internal lateinit var baseApiUrl: HttpUrl
@Inject
lateinit var networkPrefs: NetworkPrefs
internal lateinit var networkPrefs: NetworkPrefs
@Inject
lateinit var extraHeaderProvider: ExtraHeaderProvider
internal lateinit var extraHeaderProvider: ExtraHeaderProvider
private val input: Input by lazy { requireNotNull(intent?.extras?.getParcelable(ARG_INPUT)) }
private val successUrlRegex by lazy { input.successUrlRegex?.toRegex() }
@@ -114,7 +133,7 @@ class ProtonWebViewActivity : ProtonSecureActivity<ProtonWebviewActivityBinding>
finish()
}
inner class CustomWebViewClient(
internal inner class CustomWebViewClient(
private val shouldInterceptRequest: (request: WebResourceRequest) -> WebResourceResponse?,
private val onPageLoadSuccess: () -> Unit,
private val onPageLoadError: (Int?) -> Unit,
@@ -157,7 +176,7 @@ class ProtonWebViewActivity : ProtonSecureActivity<ProtonWebviewActivityBinding>
}
@Parcelize
data class Input(
public data class Input(
val url: String,
val successUrlRegex: String? = null,
val errorUrlRegex: String? = null,
@@ -171,32 +190,32 @@ class ProtonWebViewActivity : ProtonSecureActivity<ProtonWebviewActivityBinding>
) : Parcelable
@Parcelize
sealed class Result(
open val pageLoadErrorCode: Int?
public sealed class Result(
public open val pageLoadErrorCode: Int?
) : Parcelable {
data class Cancel(
public data class Cancel(
override val pageLoadErrorCode: Int?
) : Result(pageLoadErrorCode)
data class Success(
public data class Success(
val url: String,
override val pageLoadErrorCode: Int?
) : Result(pageLoadErrorCode = null)
data class Error(
public data class Error(
val url: String,
override val pageLoadErrorCode: Int?
) : Result(pageLoadErrorCode)
}
companion object {
const val ARG_INPUT = "arg.protonWebViewActivityInput"
const val ARG_RESULT = "arg.protonWebViewActivityResult"
public companion object {
internal const val ARG_INPUT = "arg.protonWebViewActivityInput"
internal const val ARG_RESULT = "arg.protonWebViewActivityResult"
object ResultContract : ActivityResultContract<Input, Result?>() {
public object ResultContract : ActivityResultContract<Input, Result?>() {
override fun createIntent(context: Context, input: Input) =
override fun createIntent(context: Context, input: Input): Intent =
Intent(context, ProtonWebViewActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
putExtra(ARG_INPUT, input)
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Proton Technologies AG
* Copyright (c) 2024 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.presentation.ui.webview
package me.proton.core.network.presentation.ui.webview
import android.annotation.SuppressLint
import android.net.Uri
@@ -36,7 +36,7 @@ import me.proton.core.presentation.utils.openBrowserLink
* - Proton Extra Headers.
*/
// See: https://commonsware.com/blog/2015/06/11/psa-webview-regression.html.
open class ProtonWebViewClient(
public open class ProtonWebViewClient(
private val networkPrefs: NetworkPrefs,
private val extraHeaderProvider: ExtraHeaderProvider,
) : WebViewClient() {
@@ -46,9 +46,9 @@ open class ProtonWebViewClient(
private var isFinished = false
var shouldOpenLinkInBrowser = true
public var shouldOpenLinkInBrowser: Boolean = true
fun Uri.isAlternativeHost() = alternativeUrl?.let { host == it.host } ?: false
public fun Uri.isAlternativeHost(): Boolean = alternativeUrl?.let { host == it.host } ?: false
override fun onPageFinished(view: WebView?, url: String?) {
isFinished = true
@@ -68,7 +68,7 @@ open class ProtonWebViewClient(
return false
}
open fun shouldKeepInWebView(url: String): Boolean {
public open fun shouldKeepInWebView(url: String): Boolean {
if (!isFinished) return true
return false
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Proton Technologies AG
* Copyright (c) 2024 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.presentation.ui.webview
package me.proton.core.network.presentation.ui.webview
import android.net.http.SslCertificate
import android.os.Build
@@ -25,15 +25,15 @@ import me.proton.core.network.data.di.Constants
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
fun SslCertificate.isTrustedByLeafSPKIPinning() =
public fun SslCertificate.isTrustedByLeafSPKIPinning(): Boolean =
getCompatX509Cert()?.isTrustedByLeafSPKIPinning() ?: false
fun X509Certificate.isTrustedByLeafSPKIPinning() =
public fun X509Certificate.isTrustedByLeafSPKIPinning(): Boolean =
LeafSPKIPinningTrustManager(Constants.ALTERNATIVE_API_SPKI_PINS).runCatching {
checkServerTrusted(arrayOf(this@isTrustedByLeafSPKIPinning), "generic")
}.isSuccess
fun SslCertificate.getCompatX509Cert(): X509Certificate? = when (Build.VERSION.SDK_INT) {
public fun SslCertificate.getCompatX509Cert(): X509Certificate? = when (Build.VERSION.SDK_INT) {
in Build.VERSION_CODES.Q..Int.MAX_VALUE -> x509Certificate
else -> {
// Hidden API, there is no way to access this value otherwise.
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2024 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ProtonCore is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.network.presentation.util
import android.content.res.Resources
import me.proton.core.network.domain.ApiException
import me.proton.core.network.domain.ApiResult
import me.proton.core.presentation.R
/**
* Return localised and user readable error message.
*/
@Suppress("UseIfInsteadOfWhen")
public fun Throwable.getUserMessage(resources: Resources): String? = when (this) {
// All api errors are wrapped with ApiException.
is ApiException -> getUserMessage(resources)
// Currently all other errors return their original message.
else -> message
}
internal fun ApiException.getUserMessage(resources: Resources): String? = when (error) {
is ApiResult.Error.Certificate,
is ApiResult.Error.Connection -> resources.getString(R.string.presentation_general_connection_error)
is ApiResult.Error.Http,
is ApiResult.Error.Parse -> message
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Proton Technologies AG
* Copyright (c) 2024 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.presentation.utils
package me.proton.core.network.presentation.util
import android.content.res.Resources
import io.mockk.every
+1
View File
@@ -58,6 +58,7 @@ dependencies {
implementation(
// Core
project(Module.kotlinUtil),
project(Module.networkPresentation),
// Features
project(Module.countryPresentation),
@@ -43,7 +43,7 @@ import me.proton.core.payment.presentation.viewmodel.BillingCommonViewModel
import me.proton.core.payment.presentation.viewmodel.BillingViewModel
import me.proton.core.plan.domain.entity.SubscriptionManagement
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.onClick
import me.proton.core.util.kotlin.CoreLogger
import me.proton.core.util.kotlin.exhaustive
@@ -46,7 +46,7 @@ import me.proton.core.payment.presentation.viewmodel.BillingCommonViewModel
import me.proton.core.payment.presentation.viewmodel.PaymentOptionsViewModel
import me.proton.core.plan.domain.entity.SubscriptionManagement
import me.proton.core.presentation.ui.adapter.selectableProtonAdapter
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
import me.proton.core.util.kotlin.exhaustive
@@ -43,7 +43,7 @@ import me.proton.core.payment.presentation.viewmodel.PaymentTokenApprovalViewMod
import me.proton.core.payment.domain.entity.PaymentTokenStatus
import me.proton.core.payment.domain.entity.ProtonPaymentToken
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.onClick
import me.proton.core.util.kotlin.exhaustive
@@ -48,7 +48,7 @@ import me.proton.core.payment.presentation.R
import me.proton.core.plan.domain.entity.SubscriptionManagement
import me.proton.core.plan.domain.usecase.PerformSubscribe
import me.proton.core.plan.domain.usecase.ValidateSubscriptionPlan
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.test.android.ArchTest
import me.proton.core.test.kotlin.CoroutinesTest
import me.proton.core.test.kotlin.assertIs
@@ -52,7 +52,7 @@ import me.proton.core.plan.domain.entity.SubscriptionManagement
import me.proton.core.plan.domain.usecase.GetCurrentSubscription
import me.proton.core.plan.domain.usecase.PerformSubscribe
import me.proton.core.plan.domain.usecase.ValidateSubscriptionPlan
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.test.android.ArchTest
import me.proton.core.test.kotlin.CoroutinesTest
import me.proton.core.test.kotlin.assertIs
@@ -34,7 +34,7 @@ import me.proton.core.payment.domain.entity.PaymentTokenStatus
import me.proton.core.payment.domain.entity.ProtonPaymentToken
import me.proton.core.payment.domain.usecase.GetPaymentTokenStatus
import me.proton.core.payment.presentation.entity.SecureEndpoint
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.test.android.ArchTest
import me.proton.core.test.kotlin.CoroutinesTest
import me.proton.core.test.kotlin.assertIs
+1
View File
@@ -63,6 +63,7 @@ dependencies {
implementation(
project(Module.kotlinUtil),
project(Module.networkPresentation),
project(Module.planData),
`android-ktx`,
`coroutines-core`,
@@ -49,7 +49,7 @@ import me.proton.core.plan.presentation.viewmodel.DynamicPlanListViewModel.State
import me.proton.core.plan.presentation.entity.DynamicUser
import me.proton.core.presentation.ui.ProtonFragment
import me.proton.core.presentation.utils.formatCentsPriceDefaultLocale
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.viewBinding
import java.util.Objects
@@ -38,7 +38,7 @@ import me.proton.core.plan.presentation.viewmodel.DynamicSelectPlanViewModel.Act
import me.proton.core.plan.presentation.viewmodel.DynamicSelectPlanViewModel.State
import me.proton.core.plan.presentation.entity.DynamicUser
import me.proton.core.presentation.utils.addOnBackPressedCallback
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.viewBinding
@@ -37,7 +37,7 @@ import me.proton.core.plan.presentation.viewmodel.DynamicSubscriptionViewModel.S
import me.proton.core.plan.presentation.entity.DynamicUser
import me.proton.core.presentation.ui.ProtonFragment
import me.proton.core.presentation.utils.formatCentsPriceDefaultLocale
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.viewBinding
@@ -43,7 +43,7 @@ import me.proton.core.plan.presentation.viewmodel.DynamicUpgradePlanViewModel.Ac
import me.proton.core.plan.presentation.viewmodel.DynamicUpgradePlanViewModel.Action.SetUser
import me.proton.core.plan.presentation.viewmodel.DynamicUpgradePlanViewModel.State
import me.proton.core.presentation.ui.ProtonFragment
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.viewBinding
@@ -40,7 +40,7 @@ import me.proton.core.plan.presentation.viewmodel.BasePlansViewModel
import me.proton.core.plan.presentation.viewmodel.SignupPlansViewModel
import me.proton.core.presentation.utils.addOnBackPressedCallback
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.viewBinding
import me.proton.core.util.kotlin.exhaustive
@@ -51,7 +51,7 @@ import me.proton.core.plan.presentation.viewmodel.BasePlansViewModel
import me.proton.core.plan.presentation.viewmodel.UpgradePlansViewModel
import me.proton.core.presentation.utils.addOnBackPressedCallback
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.launchOnScreenView
import me.proton.core.presentation.utils.viewBinding
import me.proton.core.util.kotlin.exhaustive
@@ -26,8 +26,8 @@ import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.runtime.structuralEqualityPolicy
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import me.proton.core.presentation.utils.ProtonColorUtils.intenseColorVariant
import me.proton.core.presentation.utils.ProtonColorUtils.strongColorVariant
import me.proton.core.compose.util.ProtonColorUtils.intenseColorVariant
import me.proton.core.compose.util.ProtonColorUtils.strongColorVariant
private object ProtonPalette {
val Haiti = Color(0xFF1B1340)
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Proton Technologies AG
* Copyright (c) 2024 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
@@ -16,7 +16,7 @@
* along with ProtonCore. If not, see <https://www.gnu.org/licenses/>.
*/
package me.proton.core.presentation.utils
package me.proton.core.compose.util
import android.content.Context
import android.graphics.Color
-2
View File
@@ -43,7 +43,6 @@ android {
dependencies {
api(
project(Module.networkDomain),
activity,
appcompat,
`constraint-layout`,
@@ -61,7 +60,6 @@ dependencies {
implementation(
project(Module.kotlinUtil),
project(Module.networkData),
`android-ktx`,
`core-splashscreen`,
drawerLayout,
@@ -31,11 +31,6 @@
android:name=".ui.alert.ForceUpdateActivity"
android:theme="@style/ProtonTheme.Transparent" />
<activity
android:name="me.proton.core.presentation.ui.ProtonWebViewActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
</application>
</manifest>
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Proton Technologies AG
* Copyright (c) 2024 Proton Technologies AG
* This file is part of Proton AG and ProtonCore.
*
* ProtonCore is free software: you can redistribute it and/or modify
@@ -19,25 +19,10 @@
package me.proton.core.presentation.utils
import android.content.res.Resources
import me.proton.core.network.domain.ApiException
import me.proton.core.network.domain.ApiResult
import me.proton.core.presentation.R
/**
* Return localised and user readable error message.
*/
@Suppress("UseIfInsteadOfWhen")
fun Throwable.getUserMessage(resources: Resources): String? = when (this) {
// All api errors are wrapped with ApiException.
is ApiException -> getUserMessage(resources)
// Currently all other errors return their original message.
else -> message
}
internal fun ApiException.getUserMessage(resources: Resources): String? = when (error) {
is ApiResult.Error.Certificate,
is ApiResult.Error.Connection,
is ApiResult.Error.Timeout -> resources.getString(R.string.presentation_general_connection_error)
is ApiResult.Error.Http,
is ApiResult.Error.Parse -> message
}
@Deprecated(
"Moved to network-presentation",
ReplaceWith("getUserMessage(resources)", "me.proton.core.network.presentation.util.getUserMessage"),
DeprecationLevel.ERROR
)
fun Throwable.getUserMessage(resources: Resources): String? = error("Not implemented")
@@ -50,7 +50,7 @@ import me.proton.core.presentation.utils.InputValidationResult
import me.proton.core.presentation.utils.InvalidPasswordProvider
import me.proton.core.presentation.utils.addOnBackPressedCallback
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.onFailure
@@ -35,7 +35,7 @@ import me.proton.core.presentation.ui.ProtonFragment
import me.proton.core.presentation.ui.alert.FragmentDialogResultLauncher
import me.proton.core.presentation.utils.addOnBackPressedCallback
import me.proton.core.presentation.utils.errorSnack
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.presentation.utils.hideKeyboard
import me.proton.core.presentation.utils.onClick
import me.proton.core.presentation.utils.onFailure
@@ -27,7 +27,7 @@ import me.proton.core.crypto.common.keystore.KeyStoreCrypto
import me.proton.core.domain.entity.UserId
import me.proton.core.network.domain.ApiException
import me.proton.core.network.domain.ApiResult
import me.proton.core.presentation.utils.getUserMessage
import me.proton.core.network.presentation.util.getUserMessage
import me.proton.core.test.android.ArchTest
import me.proton.core.test.kotlin.CoroutinesTest
import me.proton.core.test.kotlin.assertIs