Skip to content

Commit

Permalink
Kotlin multiplatform specific documentation added.
Browse files Browse the repository at this point in the history
Updated screenshots with updated changes for KMM.
  • Loading branch information
shafayathossain committed Apr 13, 2024
1 parent 0008695 commit 03eeeb1
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 13 deletions.
64 changes: 57 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ fun ExampleOtpScreen() {
OtpInputField(
otp = otpValue,
count = 4,
otpBoxModifier = Modifier.border(1.dp, Color.Black).background(Color.White),
otpBoxModifier = Modifier
.border(3.pxToDp(), Color.Black)
.background(Color.White),
otpTextType = KeyboardType.Number
)
}
Expand All @@ -47,12 +49,11 @@ Enable character masking for enhanced security, suitable for PINs or passwords:
```kotlin
OtpInputField(
otp = otpValue,
count = 5,
count = 4,
otpTextType = KeyboardType.NumberPassword,
otpBoxModifier = Modifier
.border(1.dp, Color.Gray)
.border(3.pxToDp(), Color.Gray)
.background(Color.White)
.padding(4.dp) // Padding inside OTP boxes should be handled carefully
)
```
![Secure Input](readmeassets/secure_input.png?raw=true "Secure Setup")
Expand All @@ -69,8 +70,7 @@ OtpInputField(
count = 5,
textColor = Color.White,
otpBoxModifier = Modifier
.size(50.dp)
.border(2.dp, Color(0xFF277F51), shape = RoundedCornerShape(4.dp))
.border(7.pxToDp(), Color(0xFF277F51), shape = RoundedCornerShape(12.pxToDp()))
)
```
![Boxy Design](readmeassets/boxy_otp_field.png?raw=true "Boxy Design")
Expand All @@ -84,7 +84,7 @@ OtpInputField(
otp = otpValue,
count = 5,
otpBoxModifier = Modifier
.bottomStroke(color = Color.DarkGray, strokeWidth = 2.dp)
.bottomStroke(color = Color.DarkGray, strokeWidth = 6.pxToDp())
)
```
![Underline Design](readmeassets/underline_otp_field.png?raw=true "Underline Design")
Expand All @@ -102,4 +102,54 @@ OtpInputField(
- **textColor**: A `Color` used to set the text color within each OTP box. This parameter provides the ability to customize the color of the text inside the OTP boxes, allowing for better integration with the overall design theme of the application.


### Rationale Behind Using `pxToDp` Instead of `.dp` Directly

The OTP Field component was initially designed for Android using Jetpack Compose, but with an eye toward compatibility and ease of adaptation for Kotlin Multiplatform Mobile (KMM) projects. This foresight influenced the decision to use pxToDp instead of directly using .dp. The approach was chosen to ensure that the component could be ported to KMM projects with minimal changes, accommodating the unique rendering behaviors on different platforms, especially iOS.

#### Issue with Standard `.dp` Usage

While .dp (density-independent pixels) is effective for scaling UI elements appropriately on Android, it often leads to inconsistent sizing on iOS devices within KMM projects. This discrepancy occurs because .dp units do not automatically adjust to the screen densities of iOS devices, leading to UI elements that do not appear as intended when shared between Android and iOS.

#### Implementing `pxToDp`

To address these challenges and ensure a seamless user experience across both platforms, the `pxToDp` function was implemented. This custom function calculates density-independent pixels by explicitly considering the screen density at runtime, ensuring that dimensions remain consistent and visually proportionate across all devices.

```kotlin
@Composable
fun Dp.dpToPx() = with(LocalDensity.current) { this@dpToPx.toPx() }

@Composable
fun Int.pxToDp() = with(LocalDensity.current) { this@pxToDp.toDp() }
```

The adoption of `pxToDp` in the OTP Field component thus addresses a critical challenge in multiplatform development by ensuring that all users, regardless of their device, experience the UI as designed.

### Kotlin Multiplatform Mobile (KMM) Adaptation

The OTP Field component, while initially designed for Android, can be adapted for use in Kotlin Multiplatform Mobile projects with some specific modifications. This ensures that the widget is functional and visually consistent on both Android and iOS platforms.

#### Necessary Modifications for Porting

To effectively port the OTP Field component to KMM, a key modification involves replacing `LocalConfiguration.current.screenWidthDp` with `LocalWindowInfo.current.containerSize.width`. This change ensures that dimensions are calculated based on the actual container size, which is critical for proper scaling on different devices:

```kotlin
val screenWidth = LocalWindowInfo.current.containerSize.width
```

#### Known Issue on iOS

There is a recognized issue with the `BasicTextField` on iOS, where the cursor in an empty `BasicTextField` aligns only to the left side (start) when `TextAlign` is set to right (end). This issue can affect the user experience on iOS, particularly in scenarios where text alignment is crucial. The problem is documented in the JetBrains Compose Multiplatform repository:

- **Similar Issue Link**: [GitHub Issue #4611](https://github.com/JetBrains/compose-multiplatform/issues/4611)


<p align="center">
<img src="readmeassets/ios_recording.gif?raw=true" alt="Demo">
</p>







11 changes: 5 additions & 6 deletions app/src/main/java/com/example/otpfield/OtpInputField.kt
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ fun OtpView_Preivew() {
mutableStateOf("124")
}
Column(
modifier = Modifier.padding(20.pxToDp()),
modifier = Modifier.padding(40.pxToDp()),
verticalArrangement = Arrangement.spacedBy(20.pxToDp())
) {
OtpInputField(
Expand All @@ -366,27 +366,26 @@ fun OtpView_Preivew() {

OtpInputField(
otp = otpValue,
count = 5,
count = 4,
otpTextType = KeyboardType.NumberPassword,
otpBoxModifier = Modifier
.border(1.pxToDp(), Color.Gray)
.border(3.pxToDp(), Color.Gray)
.background(Color.White)
.padding(4.pxToDp()) // Padding inside OTP boxes should be handled carefully
)

OtpInputField(
otp = otpValue,
count = 5,
textColor = MaterialTheme.colorScheme.onBackground,
otpBoxModifier = Modifier
.border(2.pxToDp(), Color(0xFF277F51), shape = RoundedCornerShape(4.pxToDp()))
.border(7.pxToDp(), Color(0xFF277F51), shape = RoundedCornerShape(12.pxToDp()))
)

OtpInputField(
otp = otpValue,
count = 5,
otpBoxModifier = Modifier
.bottomStroke(color = Color.DarkGray, strokeWidth = 2.pxToDp())
.bottomStroke(color = Color.DarkGray, strokeWidth = 6.pxToDp())
)
}
}
Expand Down
Binary file modified readmeassets/basic_setup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified readmeassets/boxy_otp_field.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added readmeassets/ios_recording.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified readmeassets/secure_input.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified readmeassets/underline_otp_field.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 03eeeb1

Please sign in to comment.