-
Notifications
You must be signed in to change notification settings - Fork 727
Add initial UI for NFC scanning #13299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
9 changes: 9 additions & 0 deletions
9
paymentsheet/res/drawable/stripe_ic_material_nfc_coil_bar1.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="80dp" | ||
| android:height="80dp" | ||
| android:viewportWidth="80" | ||
| android:viewportHeight="80"> | ||
| <path | ||
| android:pathData="M26.8975 47.0833 C27.3464 45.955 27.7139 44.7969 28 43.6092 C28.2861 42.4208 28.4292 41.2178 28.4292 40 C28.4292 38.7822 28.2947 37.5708 28.0258 36.3658 C27.7564 35.1603 27.3631 34.0106 26.8458 32.9167 L23.3017 34.2308 C23.7844 35.0897 24.1294 36.015 24.3367 37.0067 C24.5439 37.9978 24.6475 38.9956 24.6475 40 C24.6475 41.0044 24.5214 41.9969 24.2692 42.9775 C24.0169 43.9581 23.6944 44.9058 23.3017 45.8208 Z" | ||
| android:fillColor="#FFFFFF" /> | ||
| </vector> |
9 changes: 9 additions & 0 deletions
9
paymentsheet/res/drawable/stripe_ic_material_nfc_coil_bar2.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="80dp" | ||
| android:height="80dp" | ||
| android:viewportWidth="80" | ||
| android:viewportHeight="80"> | ||
| <path | ||
| android:pathData="M38.1025 51.7692 C38.8764 49.8992 39.4331 47.975 39.7725 45.9967 C40.1119 44.0183 40.2817 42.02 40.2817 40.0017 C40.2817 37.9833 40.1119 35.9933 39.7725 34.0317 C39.4331 32.0694 38.8764 30.1636 38.1025 28.3142 L34.5067 29.5642 C35.2328 31.2008 35.7467 32.8983 36.0483 34.6567 C36.3494 36.4156 36.5 38.1967 36.5 40 C36.5 41.8033 36.3408 43.5928 36.0225 45.3683 C35.7042 47.1439 35.1989 48.8608 34.5067 50.5192 Z" | ||
| android:fillColor="#FFFFFF" /> | ||
| </vector> |
9 changes: 9 additions & 0 deletions
9
paymentsheet/res/drawable/stripe_ic_material_nfc_coil_bar3.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="80dp" | ||
| android:height="80dp" | ||
| android:viewportWidth="80" | ||
| android:viewportHeight="80"> | ||
| <path | ||
| android:pathData="M49.0192 56.3717 C50.0919 53.7572 50.8794 51.0822 51.3817 48.3467 C51.8833 45.6111 52.1342 42.8289 52.1342 40 C52.1342 37.1711 51.8833 34.3889 51.3817 31.6533 C50.8794 28.9178 50.0919 26.2597 49.0192 23.6792 L45.4742 25.0958 C46.4575 27.4492 47.1831 29.8736 47.6508 32.3692 C48.1186 34.8647 48.3525 37.4058 48.3525 39.9925 C48.3525 42.5786 48.1186 45.1353 47.6508 47.6625 C47.1831 50.1897 46.4575 52.6205 45.4742 54.955 Z" | ||
| android:fillColor="#FFFFFF" /> | ||
| </vector> |
10 changes: 10 additions & 0 deletions
10
paymentsheet/res/drawable/stripe_ic_material_nfc_coil_circle.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||
| android:width="80dp" | ||
| android:height="80dp" | ||
| android:viewportWidth="80" | ||
| android:viewportHeight="80"> | ||
| <path | ||
| android:pathData="M40.0058 71.6667 C35.6603 71.6667 31.5658 70.8356 27.7225 69.1733 C23.8792 67.5111 20.5183 65.2414 17.64 62.3642 C14.7617 59.4869 12.4908 56.1275 10.8275 52.2858 C9.16472 48.4447 8.33333 44.3514 8.33333 40.0058 C8.33333 35.6258 9.16444 31.5089 10.8267 27.655 C12.4889 23.8011 14.7586 20.4489 17.6358 17.5983 C20.5131 14.7478 23.8725 12.4908 27.7142 10.8275 C31.5553 9.16472 35.6486 8.33333 39.9942 8.33333 C44.3742 8.33333 48.4911 9.16444 52.345 10.8267 C56.1989 12.4889 59.5511 14.7447 62.4017 17.5942 C65.2522 20.4436 67.5092 23.7944 69.1725 27.6467 C70.8353 31.4989 71.6667 35.6147 71.6667 39.9942 C71.6667 44.3397 70.8356 48.4342 69.1733 52.2775 C67.5111 56.1208 65.2553 59.4817 62.4058 62.36 C59.5564 65.2383 56.2056 67.5092 52.3533 69.1725 C48.5011 70.8353 44.3853 71.6667 40.0058 71.6667Z M40 67.8842 C47.7606 67.8842 54.3481 65.1686 59.7625 59.7375 C65.1769 54.3058 67.8842 47.7267 67.8842 40 C67.8842 32.2394 65.1769 25.6519 59.7625 20.2375 C54.3481 14.8231 47.7606 12.1158 40 12.1158 C32.2733 12.1158 25.6942 14.8231 20.2625 20.2375 C14.8314 25.6519 12.1158 32.2394 12.1158 40 C12.1158 47.7267 14.8314 54.3058 20.2625 59.7375 C25.6942 65.1686 32.2733 67.8842 40 67.8842Z" | ||
| android:fillColor="#FFFFFF" | ||
| android:fillType="evenOdd" /> | ||
| </vector> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 52 additions & 3 deletions
55
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/NfcScanningActivity.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,70 @@ | ||
| package com.stripe.android.common.nfcscan | ||
|
|
||
| import android.content.Intent | ||
| import android.os.Bundle | ||
| import androidx.activity.SystemBarStyle | ||
| import androidx.activity.compose.setContent | ||
| import androidx.activity.enableEdgeToEdge | ||
| import androidx.activity.viewModels | ||
| import androidx.appcompat.app.AppCompatActivity | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.lifecycle.lifecycleScope | ||
| import com.stripe.android.common.nfcscan.ui.NfcScanningScreen | ||
| import com.stripe.android.common.nfcscan.ui.NfcScanningTheme | ||
| import com.stripe.android.uicore.utils.collectAsState | ||
| import kotlinx.coroutines.flow.collectLatest | ||
| import kotlinx.coroutines.launch | ||
| import android.graphics.Color as AndroidColor | ||
|
|
||
| internal class NfcScanningActivity : AppCompatActivity() { | ||
| private val viewModel by viewModels<NfcScanningViewModel> { | ||
| NfcScanningViewModel.factory() | ||
| } | ||
|
|
||
| override fun onCreate(savedInstanceState: Bundle?) { | ||
| super.onCreate(savedInstanceState) | ||
|
|
||
| lifecycleScope.launch { | ||
| viewModel.result.collectLatest { result -> | ||
| finishWithResult(result) | ||
| } | ||
| } | ||
|
|
||
| enableEdgeToEdge( | ||
| statusBarStyle = SystemBarStyle.light( | ||
| scrim = AndroidColor.TRANSPARENT, | ||
| darkScrim = AndroidColor.TRANSPARENT, | ||
| ), | ||
| navigationBarStyle = SystemBarStyle.light( | ||
| scrim = AndroidColor.TRANSPARENT, | ||
| darkScrim = AndroidColor.TRANSPARENT, | ||
| ), | ||
| ) | ||
|
|
||
| setContent { | ||
| NfcScanningTheme { | ||
| val viewState by viewModel.viewState.collectAsState() | ||
|
|
||
| NfcScanningScreen( | ||
| state = viewState, | ||
| viewActionHandler = viewModel::handleViewAction, | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| override fun onStop() { | ||
| super.onStop() | ||
| if (!isFinishing && !isChangingConfigurations) { | ||
| setResult(NfcScanningContract.Result.Canceled) | ||
| finish() | ||
| finishWithResult(NfcScanningContract.Result.Canceled) | ||
| } | ||
| } | ||
|
|
||
| private fun setResult(result: NfcScanningContract.Result) { | ||
| private fun finishWithResult(result: NfcScanningContract.Result) { | ||
| setResult( | ||
| RESULT_OK, | ||
| Intent().putExtras(result.toBundle()), | ||
| ) | ||
| finish() | ||
| } | ||
| } |
5 changes: 5 additions & 0 deletions
5
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/NfcScanningViewAction.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package com.stripe.android.common.nfcscan | ||
|
|
||
| internal sealed interface NfcScanningViewAction { | ||
| data object Close : NfcScanningViewAction | ||
| } |
48 changes: 48 additions & 0 deletions
48
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/NfcScanningViewModel.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package com.stripe.android.common.nfcscan | ||
|
|
||
| import androidx.lifecycle.ViewModel | ||
| import androidx.lifecycle.ViewModelProvider | ||
| import androidx.lifecycle.viewModelScope | ||
| import androidx.lifecycle.viewmodel.initializer | ||
| import androidx.lifecycle.viewmodel.viewModelFactory | ||
| import com.stripe.android.common.nfcscan.tapzone.TapZoneResolver | ||
| import com.stripe.android.core.utils.requireApplication | ||
| import com.stripe.android.uicore.utils.stateFlowOf | ||
| import kotlinx.coroutines.flow.MutableSharedFlow | ||
| import kotlinx.coroutines.flow.StateFlow | ||
| import kotlinx.coroutines.flow.asSharedFlow | ||
| import kotlinx.coroutines.launch | ||
| import javax.inject.Inject | ||
|
|
||
| internal class NfcScanningViewModel @Inject constructor( | ||
| tapZoneResolver: TapZoneResolver, | ||
| ) : ViewModel() { | ||
| private val tapZone = tapZoneResolver.get() | ||
|
|
||
| private val _result = MutableSharedFlow<NfcScanningContract.Result>() | ||
| val result = _result.asSharedFlow() | ||
|
|
||
| val viewState: StateFlow<NfcScanningViewState> = stateFlowOf(NfcScanningViewState(tapZone)) | ||
|
|
||
| fun handleViewAction(viewAction: NfcScanningViewAction) { | ||
| when (viewAction) { | ||
| is NfcScanningViewAction.Close -> { | ||
| viewModelScope.launch { | ||
| _result.emit(NfcScanningContract.Result.Canceled) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| companion object { | ||
| fun factory(): ViewModelProvider.Factory { | ||
| return viewModelFactory { | ||
| initializer<NfcScanningViewModel> { | ||
| DaggerNfcScanningViewModelComponent.factory() | ||
| .create(requireApplication()) | ||
| .viewModel | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
30 changes: 30 additions & 0 deletions
30
...entsheet/src/main/java/com/stripe/android/common/nfcscan/NfcScanningViewModelComponent.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| package com.stripe.android.common.nfcscan | ||
|
|
||
| import android.app.Application | ||
| import com.stripe.android.common.nfcscan.hardware.NfcHardwareDelegateModule | ||
| import com.stripe.android.common.nfcscan.tapzone.TapZoneModule | ||
| import dagger.BindsInstance | ||
| import dagger.Component | ||
| import dagger.Module | ||
|
|
||
| @Component( | ||
| modules = [NfcScanningViewModelModule::class] | ||
| ) | ||
| internal interface NfcScanningViewModelComponent { | ||
| val viewModel: NfcScanningViewModel | ||
|
|
||
| @Component.Factory | ||
| interface Factory { | ||
| fun create( | ||
| @BindsInstance application: Application, | ||
| ): NfcScanningViewModelComponent | ||
| } | ||
| } | ||
|
|
||
| @Module( | ||
| includes = [ | ||
| NfcHardwareDelegateModule::class, | ||
| TapZoneModule::class, | ||
| ] | ||
| ) | ||
| internal interface NfcScanningViewModelModule |
7 changes: 7 additions & 0 deletions
7
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/NfcScanningViewState.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.stripe.android.common.nfcscan | ||
|
|
||
| import com.stripe.android.common.nfcscan.tapzone.TapZone | ||
|
|
||
| internal data class NfcScanningViewState( | ||
| val tapZone: TapZone, | ||
| ) |
6 changes: 6 additions & 0 deletions
6
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/tapzone/TapZone.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package com.stripe.android.common.nfcscan.tapzone | ||
|
|
||
| internal data class TapZone( | ||
| val xBias: Float, | ||
| val yBias: Float, | ||
| ) |
10 changes: 10 additions & 0 deletions
10
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/tapzone/TapZoneModule.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.stripe.android.common.nfcscan.tapzone | ||
|
|
||
| import dagger.Binds | ||
| import dagger.Module | ||
|
|
||
| @Module | ||
| internal interface TapZoneModule { | ||
| @Binds | ||
| fun bindsTapZoneResolver(resolver: DefaultTapZoneResolver): TapZoneResolver | ||
| } |
17 changes: 17 additions & 0 deletions
17
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/tapzone/TapZoneResolver.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.stripe.android.common.nfcscan.tapzone | ||
|
|
||
| import javax.inject.Inject | ||
|
|
||
| internal interface TapZoneResolver { | ||
| fun get(): TapZone | ||
| } | ||
|
|
||
| internal class DefaultTapZoneResolver @Inject constructor() : TapZoneResolver { | ||
| override fun get(): TapZone { | ||
| return DEFAULT | ||
| } | ||
|
|
||
| private companion object { | ||
| val DEFAULT = TapZone(xBias = 0.5f, yBias = 0.5f) | ||
| } | ||
| } |
43 changes: 43 additions & 0 deletions
43
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/ui/DeviceRotation.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package com.stripe.android.common.nfcscan.ui | ||
|
|
||
| import android.content.Context | ||
| import android.os.Build | ||
| import android.view.Surface | ||
| import android.view.WindowManager | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.ui.platform.LocalContext | ||
|
|
||
| internal enum class DeviceRotation { | ||
| Portrait, | ||
| LandscapeLeft, | ||
| LandscapeRight, | ||
| UpsideDown | ||
| } | ||
|
|
||
| @Composable | ||
| internal fun rememberDeviceRotation(): DeviceRotation { | ||
| val context = LocalContext.current | ||
|
|
||
| return remember(context) { | ||
| context.getDeviceRotation() | ||
| } | ||
| } | ||
|
|
||
| internal fun Context.getDeviceRotation(): DeviceRotation { | ||
| @Suppress("DEPRECATION") | ||
| val display = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { | ||
| display | ||
| } else { | ||
| val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager | ||
| windowManager.defaultDisplay | ||
| } | ||
|
|
||
| return when (display?.rotation) { | ||
| Surface.ROTATION_0 -> DeviceRotation.Portrait | ||
| Surface.ROTATION_90 -> DeviceRotation.LandscapeLeft | ||
| Surface.ROTATION_180 -> DeviceRotation.UpsideDown | ||
| Surface.ROTATION_270 -> DeviceRotation.LandscapeRight | ||
| else -> DeviceRotation.Portrait | ||
| } | ||
| } | ||
51 changes: 51 additions & 0 deletions
51
paymentsheet/src/main/java/com/stripe/android/common/nfcscan/ui/NfcCloseButton.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package com.stripe.android.common.nfcscan.ui | ||
|
|
||
| import androidx.compose.foundation.background | ||
| import androidx.compose.foundation.border | ||
| import androidx.compose.foundation.clickable | ||
| import androidx.compose.foundation.isSystemInDarkTheme | ||
| import androidx.compose.foundation.layout.Box | ||
| import androidx.compose.foundation.layout.size | ||
| import androidx.compose.foundation.shape.CircleShape | ||
| import androidx.compose.material.Icon | ||
| import androidx.compose.material.MaterialTheme | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.draw.clip | ||
| import androidx.compose.ui.draw.shadow | ||
| import androidx.compose.ui.graphics.Color | ||
| import androidx.compose.ui.res.painterResource | ||
| import androidx.compose.ui.unit.Dp | ||
| import androidx.compose.ui.unit.dp | ||
| import com.stripe.android.uicore.stripeColors | ||
| import com.stripe.android.ui.core.R as PaymentsUiCoreR | ||
|
|
||
| @Composable | ||
| internal fun NfcCloseButton( | ||
| onPress: () -> Unit, | ||
| ) { | ||
| val isDarkTheme = isSystemInDarkTheme() | ||
| val outline = if (isDarkTheme) { | ||
| Modifier.border(width = Dp.Hairline, color = Color.White.copy(alpha = 0.2f), shape = CircleShape) | ||
| } else { | ||
| Modifier.shadow(elevation = 3.dp, shape = CircleShape) | ||
| } | ||
|
|
||
| Box( | ||
| modifier = Modifier | ||
| .size(48.dp) | ||
| .then(outline) | ||
| .background(MaterialTheme.colors.surface, CircleShape) | ||
| .clip(CircleShape) | ||
| .clickable { onPress() }, | ||
| contentAlignment = Alignment.Center | ||
| ) { | ||
| Icon( | ||
| painter = painterResource(PaymentsUiCoreR.drawable.stripe_ic_rounded_close), | ||
| contentDescription = "Cancel", | ||
| tint = MaterialTheme.stripeColors.appBarIcon, | ||
| modifier = Modifier.size(16.dp) | ||
| ) | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we annotate this as @VisibleForTesting?