Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.graphics.Color
import android.os.Build
import android.view.MenuItem
import android.view.View
import android.view.View.INVISIBLE
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.WindowManager
import android.widget.ProgressBar
import android.widget.RelativeLayout
Expand All @@ -21,6 +21,8 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.Toolbar
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.children
import com.shopify.checkoutkit.ShopifyCheckoutKit.log

Expand All @@ -32,6 +34,7 @@ internal class CheckoutDialog(
) : ComponentDialog(context) {

private var presentedCheckoutWebView: CheckoutWebView? = null
private var rootPaddingBottom: Int = 0

private val backNavigationCallback = object : OnBackPressedCallback(enabled = true) {
override fun handleOnBackPressed() {
Expand All @@ -47,14 +50,9 @@ internal class CheckoutDialog(
fun start(context: ComponentActivity) {
log.d(LOG_TAG, "Dialog start called.")
setContentView(R.layout.dialog_checkout)
window?.setLayout(MATCH_PARENT, WRAP_CONTENT)
window?.setBackgroundDrawable(Color.TRANSPARENT.toDrawable())
// Although this flag is deprecated in newest targets, it's properly
// addressing the keyboard focus on the WebView within the dialog.
// The non-deprecated alternative (insets listener) does notify about
// keyboard insets when visible, but it is not adjusting the pan
// properly into the fields. To be investigated further.
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
setupKeyboardInsetHandling()

log.d(LOG_TAG, "Finding or creating WebView.")
val checkoutWebView = CheckoutWebView.checkoutViewFor(checkoutUrl, context)
Expand All @@ -69,6 +67,7 @@ internal class CheckoutDialog(

val colorScheme = ShopifyCheckoutKit.configuration.colorScheme
log.d(LOG_TAG, "Configured colorScheme $colorScheme")
findViewById<View>(R.id.checkoutKitRoot).setBackgroundColor(colorScheme.webViewBackgroundColor())
findViewById<Toolbar>(R.id.checkoutKitHeader).apply {
log.d(LOG_TAG, "Applying configured header colors and inflating menu.")
setBackgroundColor(colorScheme.headerBackgroundColor())
Expand Down Expand Up @@ -100,6 +99,29 @@ internal class CheckoutDialog(

log.d(LOG_TAG, "Showing dialog.")
show()
// Dialog window size is only applied reliably after show().
window?.setLayout(MATCH_PARENT, MATCH_PARENT)
ViewCompat.requestApplyInsets(findViewById(R.id.checkoutKitRoot))
}

private fun setupKeyboardInsetHandling() {
val root = findViewById<View>(R.id.checkoutKitRoot)
rootPaddingBottom = root.paddingBottom
ViewCompat.setOnApplyWindowInsetsListener(root) { _, insets ->
val imeBottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
applyKeyboardInset(imeBottom)
insets
}
}

internal fun applyKeyboardInset(imeBottom: Int) {
val root = findViewById<View>(R.id.checkoutKitRoot)
root.setPadding(
root.paddingLeft,
root.paddingTop,
root.paddingRight,
rootPaddingBottom + imeBottom.coerceAtLeast(0),
)
}

private fun MenuItem.setupCloseButton(colorScheme: ColorScheme) {
Expand Down Expand Up @@ -140,7 +162,7 @@ internal class CheckoutDialog(
findViewById<RelativeLayout>(R.id.checkoutKitContainer).apply {
log.d(LOG_TAG, "Found parent view, setting its colors and layout params.")
setBackgroundColor(colorScheme.webViewBackgroundColor())
val layoutParams = RelativeLayout.LayoutParams(WRAP_CONTENT, MATCH_PARENT)
val layoutParams = RelativeLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
layoutParams.addRule(RelativeLayout.BELOW, R.id.progressBar)
checkoutWebView.removeFromParent()
log.d(LOG_TAG, "Adding WebView to parent view.")
Expand Down
12 changes: 7 additions & 5 deletions platforms/android/lib/src/main/res/layout/dialog_checkout.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/checkoutKitRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent">
android:background="@android:color/transparent"
android:orientation="vertical">

<androidx.appcompat.widget.Toolbar
android:id="@+id/checkoutKitHeader"
Expand All @@ -18,9 +20,9 @@
<RelativeLayout
android:id="@+id/checkoutKitContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/transparent"
android:layout_below="@id/checkoutKitHeader"
android:visibility="visible">

<ProgressBar
Expand All @@ -32,4 +34,4 @@
android:indeterminate="false" />

</RelativeLayout>
</RelativeLayout>
</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import android.app.Dialog
import android.graphics.drawable.ColorDrawable
import android.os.Looper
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.WindowManager
import android.webkit.WebView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.activity.ComponentActivity
import androidx.appcompat.widget.Toolbar
Expand Down Expand Up @@ -63,6 +66,24 @@ class CheckoutDialogTest {
assertThat(dialog.isShowing).isTrue
}

@Test
fun `dialog fills height and handles keyboard with insets`() {
ShopifyCheckoutKit.present("https://shopify.com", activity, processor)

val dialog = ShadowDialog.getLatestDialog()
val attributes = dialog.window?.attributes
val root = dialog.findViewById<View>(R.id.checkoutKitRoot)
val container = dialog.findViewById<RelativeLayout>(R.id.checkoutKitContainer)
val containerLayoutParams = container.layoutParams as LinearLayout.LayoutParams

assertThat(root).isInstanceOf(LinearLayout::class.java)
assertThat(attributes?.height).isEqualTo(MATCH_PARENT)
assertThat(attributes?.softInputMode?.and(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING))
.isEqualTo(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
assertThat(containerLayoutParams.height).isZero()
assertThat(containerLayoutParams.weight).isEqualTo(1f)
}

@Test
fun `checkoutView is added to the container when dialog is presented`() {
ShopifyCheckoutKit.present("https://shopify.com", activity, processor)
Expand All @@ -83,8 +104,26 @@ class CheckoutDialogTest {
val webView: WebView = ShadowDialog.getLatestDialog()
.findViewById<RelativeLayout>(R.id.checkoutKitContainer)
.children.firstOrNull { it is WebView } as WebView? ?: fail("No WebVew found in dialog")
val layoutParams = webView.layoutParams as RelativeLayout.LayoutParams

assertThat(shadowOf(webView).wasOnResumeCalled()).isTrue()
assertThat(layoutParams.width).isEqualTo(MATCH_PARENT)
assertThat(layoutParams.height).isEqualTo(MATCH_PARENT)
}

@Test
fun `ime inset changes pad checkout content without resizing window`() {
ShopifyCheckoutKit.present("https://shopify.com", activity, processor)
val dialog = ShadowDialog.getLatestDialog() as CheckoutDialog
val root = dialog.findViewById<View>(R.id.checkoutKitRoot)
dialog.window?.setLayout(MATCH_PARENT, 400)

assertThat(root.paddingBottom).isZero()

dialog.applyKeyboardInset(100)

assertThat(dialog.window?.attributes?.height).isEqualTo(400)
assertThat(root.paddingBottom).isEqualTo(100)
}

@Test
Expand Down Expand Up @@ -238,17 +277,20 @@ class CheckoutDialogTest {
}

@Test
fun `sets WebView container background color based on current configuration`() {
fun `sets checkout content background color based on current configuration`() {
val customColors = customColors()
ShopifyCheckoutKit.configuration.colorScheme = ColorScheme.Web(customColors)

ShopifyCheckoutKit.present("https://shopify.com", activity, processor)

val dialog = ShadowDialog.getLatestDialog()
val root = dialog.findViewById<View>(R.id.checkoutKitRoot)
val webViewContainer = dialog.findViewById<RelativeLayout>(R.id.checkoutKitContainer)
val rootBackgroundColor = backgroundColor(root)
val webViewContainerBackgroundColor = backgroundColor(webViewContainer)
val configuredColor = customColors.webViewBackground.getValue(activity)

assertThat(rootBackgroundColor).isEqualTo(configuredColor)
assertThat(webViewContainerBackgroundColor).isEqualTo(configuredColor)
}

Expand Down
Loading