Create sub packages.

This commit is contained in:
Benoit Marty 2023-04-24 14:49:15 +02:00 committed by Benoit Marty
parent 4c9bed9d8a
commit d33fbaf89f
15 changed files with 58 additions and 32 deletions

View file

@ -29,8 +29,9 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.login.impl.changeserver.ChangeServerNode import io.element.android.features.login.impl.changeserver.ChangeServerNode
import io.element.android.features.login.impl.oidc.CustomTabHandler import io.element.android.features.login.impl.oidc.CustomTabAvailabilityChecker
import io.element.android.features.login.impl.oidc.OidcNode import io.element.android.features.login.impl.oidc.customtab.CustomTabHandler
import io.element.android.features.login.impl.oidc.webview.OidcNode
import io.element.android.features.login.impl.root.LoginRootNode import io.element.android.features.login.impl.root.LoginRootNode
import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.BackstackNode
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
@ -43,6 +44,7 @@ import kotlinx.parcelize.Parcelize
class LoginFlowNode @AssistedInject constructor( class LoginFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
private val customTabAvailabilityChecker: CustomTabAvailabilityChecker,
private val customTabHandler: CustomTabHandler, private val customTabHandler: CustomTabHandler,
) : BackstackNode<LoginFlowNode.NavTarget>( ) : BackstackNode<LoginFlowNode.NavTarget>(
backstack = BackStack( backstack = BackStack(
@ -72,7 +74,8 @@ class LoginFlowNode @AssistedInject constructor(
} }
override fun onOidcDetails(oidcDetails: OidcDetails) { override fun onOidcDetails(oidcDetails: OidcDetails) {
if (customTabHandler.supportCustomTab()) { if (customTabAvailabilityChecker.supportCustomTab()) {
// In this case open a Chrome Custom tab
customTabHandler.open(oidcDetails.url) customTabHandler.open(oidcDetails.url)
} else { } else {
// Fallback to WebView mode // Fallback to WebView mode

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.login.impl.oidc
import android.content.Context
import androidx.browser.customtabs.CustomTabsClient
import io.element.android.libraries.di.ApplicationContext
import javax.inject.Inject
class CustomTabAvailabilityChecker @Inject constructor(
@ApplicationContext private val context: Context,
) {
/**
* Return true if the device supports Custom tab, i.e. there is an third party app with
* CustomTab support (ex: Chrome, Firefox, etc.).
*/
fun supportCustomTab(): Boolean {
val packageName = CustomTabsClient.getPackageName(context, null)
return packageName != null
}
}

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.customtab
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
@ -22,7 +22,6 @@ import android.net.Uri
import androidx.browser.customtabs.CustomTabsClient import androidx.browser.customtabs.CustomTabsClient
import androidx.browser.customtabs.CustomTabsServiceConnection import androidx.browser.customtabs.CustomTabsServiceConnection
import androidx.browser.customtabs.CustomTabsSession import androidx.browser.customtabs.CustomTabsSession
import io.element.android.features.login.impl.oidc.web.openUrlInChromeCustomTab
import io.element.android.libraries.di.ApplicationContext import io.element.android.libraries.di.ApplicationContext
import javax.inject.Inject import javax.inject.Inject
@ -33,15 +32,6 @@ class CustomTabHandler @Inject constructor(
private var customTabsClient: CustomTabsClient? = null private var customTabsClient: CustomTabsClient? = null
private var customTabsServiceConnection: CustomTabsServiceConnection? = null private var customTabsServiceConnection: CustomTabsServiceConnection? = null
/**
* Return true if the device supports Custom tab, i.e. there is an third party app with
* CustomTab support (ex: Chrome, Firefox, etc.).
*/
fun supportCustomTab(): Boolean {
val packageName = CustomTabsClient.getPackageName(context, null)
return packageName != null
}
fun prepareCustomTab(url: String) { fun prepareCustomTab(url: String) {
val packageName = CustomTabsClient.getPackageName(context, null) val packageName = CustomTabsClient.getPackageName(context, null)
@ -82,6 +72,6 @@ class CustomTabHandler @Inject constructor(
} }
fun open(url: String) { fun open(url: String) {
openUrlInChromeCustomTab(context, customTabsSession, false, url) context.openUrlInChromeCustomTab(customTabsSession, false, url)
} }
} }

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc.web package io.element.android.features.login.impl.oidc.customtab
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.features.login.api.oidc.OidcAction import io.element.android.features.login.api.oidc.OidcAction

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc.web package io.element.android.features.login.impl.oidc.customtab
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
@ -29,8 +29,7 @@ import androidx.browser.customtabs.CustomTabsSession
* If several compatible browsers are installed, the user will be proposed to choose one. * If several compatible browsers are installed, the user will be proposed to choose one.
* Ref: https://developer.chrome.com/multidevice/android/customtabs. * Ref: https://developer.chrome.com/multidevice/android/customtabs.
*/ */
fun openUrlInChromeCustomTab( fun Context.openUrlInChromeCustomTab(
context: Context,
session: CustomTabsSession?, session: CustomTabsSession?,
darkTheme: Boolean, darkTheme: Boolean,
url: String url: String
@ -58,7 +57,7 @@ fun openUrlInChromeCustomTab(
.apply { .apply {
intent.flags += Intent.FLAG_ACTIVITY_NEW_TASK intent.flags += Intent.FLAG_ACTIVITY_NEW_TASK
} }
.launchUrl(context, Uri.parse(url)) .launchUrl(this, Uri.parse(url))
} catch (activityNotFoundException: ActivityNotFoundException) { } catch (activityNotFoundException: ActivityNotFoundException) {
// TODO context.toast(R.string.error_no_external_application_found) // TODO context.toast(R.string.error_no_external_application_found)
} }

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import io.element.android.features.login.api.oidc.OidcAction import io.element.android.features.login.api.oidc.OidcAction

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.auth.OidcDetails

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import android.webkit.WebView import android.webkit.WebView
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
@ -27,9 +27,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import io.element.android.features.login.impl.oidc.OidcUrlParser
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.core.bool.orFalse import io.element.android.libraries.core.bool.orFalse
import io.element.android.libraries.core.bool.orTrue
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import android.annotation.TargetApi import android.annotation.TargetApi
import android.os.Build import android.os.Build
@ -23,7 +23,6 @@ import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import timber.log.Timber import timber.log.Timber
// TODO Move to a dedicated module
class OidcWebViewClient(private val eventListener: WebViewEventListener) : WebViewClient() { class OidcWebViewClient(private val eventListener: WebViewEventListener) : WebViewClient() {
@TargetApi(Build.VERSION_CODES.N) @TargetApi(Build.VERSION_CODES.N)
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {

View file

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
interface WebViewEventListener { interface WebViewEventListener {
/** /**

View file

@ -25,7 +25,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import io.element.android.features.login.api.oidc.OidcAction import io.element.android.features.login.api.oidc.OidcAction
import io.element.android.features.login.impl.oidc.web.DefaultOidcActionFlow import io.element.android.features.login.impl.oidc.customtab.DefaultOidcActionFlow
import io.element.android.features.login.impl.util.LoginConstants import io.element.android.features.login.impl.util.LoginConstants
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter

View file

@ -16,7 +16,7 @@
@file:OptIn(ExperimentalCoroutinesApi::class) @file:OptIn(ExperimentalCoroutinesApi::class)
package io.element.android.features.login.impl.oidc package io.element.android.features.login.impl.oidc.webview
import app.cash.molecule.RecompositionClock import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow