Skip to content
Open
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 @@ -22,7 +22,7 @@ class InputControl(
val maxLength: Int = Int.MAX_VALUE,
val keyboardOptions: KeyboardOptions,
val textTransformation: TextTransformation? = null,
val visualTransformation: VisualTransformation = VisualTransformation.Companion.None
val visualTransformation: VisualTransformation = VisualTransformation.None
) : ValidatableControl<String> {

constructor(coroutineScope: CoroutineScope) : this(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,4 @@ interface VisualTransformation {
}

fun restore(text: String): String
}

/**
* The Visual Filter can be used for password Input Field.
*
* Note that this visual filter only works for ASCII characters.
*
* @param mask The mask character used instead of original text.
*/
data class PasswordVisualTransformation(val mask: Char = '\u2022') : VisualTransformation {
constructor() : this(mask = '\u2022')

override fun filter(text: String): TransformedText {
return TransformedText(mask.toString().repeat(text.length), OffsetMapping.Identity)
}

override fun restore(text: String): String {
return text
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.input.PasswordVisualTransformation
import dev.icerock.moko.resources.compose.localized
import kotlinx.coroutines.flow.collectLatest
import ru.mobileup.kmm_form_validation.android_sample.R
import ru.mobileup.kmm_form_validation.control.InputControl
import ru.mobileup.kmm_form_validation.toCompose

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun PasswordTextField(
inputControl: ru.mobileup.kmm_form_validation.control.InputControl,
inputControl: InputControl,
label: String,
modifier: Modifier = Modifier
) {
Expand Down Expand Up @@ -64,9 +65,9 @@ fun PasswordTextField(
isError = error != null,
onValueChange = inputControl::onTextChanged,
visualTransformation = if (passwordVisibility) {
VisualTransformation.None
} else {
inputControl.visualTransformation.toCompose()
} else {
PasswordVisualTransformation()
},
trailingIcon = {
val image = if (passwordVisibility) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusChanged
import dev.icerock.moko.resources.compose.localized
import kotlinx.coroutines.flow.collectLatest
import ru.mobileup.kmm_form_validation.control.InputControl
import ru.mobileup.kmm_form_validation.toCompose

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun TextField(
inputControl: ru.mobileup.kmm_form_validation.control.InputControl,
inputControl: InputControl,
label: String,
modifier: Modifier = Modifier
) {
Expand Down
60 changes: 41 additions & 19 deletions sample/iosSample/iosSample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,27 @@
objects = {

/* Begin PBXBuildFile section */
E521689129955B3F00F366EF /* ScrolledFocusField.swift in Sources */ = {isa = PBXBuildFile; fileRef = E521689029955B3F00F366EF /* ScrolledFocusField.swift */; };
EC7C1FEA2987B251001DCE8B /* iosSampleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C1FE92987B251001DCE8B /* iosSampleApp.swift */; };
EC7C1FEC2987B251001DCE8B /* TextFieldWithControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C1FEB2987B251001DCE8B /* TextFieldWithControl.swift */; };
EC7C1FEE2987B252001DCE8B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7C1FED2987B252001DCE8B /* Assets.xcassets */; };
EC7C1FF12987B252001DCE8B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = EC7C1FF02987B252001DCE8B /* Preview Assets.xcassets */; };
EC7C20172987F483001DCE8B /* UnsafeObservableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C20162987F483001DCE8B /* UnsafeObservableState.swift */; };
EC7C201B298A6A67001DCE8B /* VisualFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C201A298A6A66001DCE8B /* VisualFormatter.swift */; };
EC7C201E298A6AD1001DCE8B /* VisualExtentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C201D298A6AD1001DCE8B /* VisualExtentions.swift */; };
EC7C2020298A6B76001DCE8B /* SecureTextFieldWithControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C201F298A6B76001DCE8B /* SecureTextFieldWithControl.swift */; };
EC7C2023298A710B001DCE8B /* ToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C2022298A710B001DCE8B /* ToggleView.swift */; };
EC7C2025298A7883001DCE8B /* SubmitButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC7C2024298A7883001DCE8B /* SubmitButtonView.swift */; };
ECB57B3B298CFC4E00AE547C /* FormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECB57B3A298CFC4E00AE547C /* FormView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
E521689029955B3F00F366EF /* ScrolledFocusField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrolledFocusField.swift; sourceTree = "<group>"; };
EC7C1FE62987B251001DCE8B /* iosSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
EC7C1FE92987B251001DCE8B /* iosSampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iosSampleApp.swift; sourceTree = "<group>"; };
EC7C1FEB2987B251001DCE8B /* TextFieldWithControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldWithControl.swift; sourceTree = "<group>"; };
EC7C1FED2987B252001DCE8B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
EC7C1FF02987B252001DCE8B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
EC7C20162987F483001DCE8B /* UnsafeObservableState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsafeObservableState.swift; sourceTree = "<group>"; };
EC7C201A298A6A66001DCE8B /* VisualFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisualFormatter.swift; sourceTree = "<group>"; };
EC7C201D298A6AD1001DCE8B /* VisualExtentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VisualExtentions.swift; sourceTree = "<group>"; };
EC7C201F298A6B76001DCE8B /* SecureTextFieldWithControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureTextFieldWithControl.swift; sourceTree = "<group>"; };
EC7C2022298A710B001DCE8B /* ToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleView.swift; sourceTree = "<group>"; };
EC7C2024298A7883001DCE8B /* SubmitButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmitButtonView.swift; sourceTree = "<group>"; };
ECB57B3A298CFC4E00AE547C /* FormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormView.swift; sourceTree = "<group>"; };
Expand All @@ -46,6 +44,38 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
E521688F29955B0E00F366EF /* ViewModifiers */ = {
isa = PBXGroup;
children = (
E521689029955B3F00F366EF /* ScrolledFocusField.swift */,
);
path = ViewModifiers;
sourceTree = "<group>";
};
E521689429955E2100F366EF /* Extensions */ = {
isa = PBXGroup;
children = (
EC7C201D298A6AD1001DCE8B /* VisualExtentions.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
E521689529955E5600F366EF /* Application */ = {
isa = PBXGroup;
children = (
EC7C1FE92987B251001DCE8B /* iosSampleApp.swift */,
);
path = Application;
sourceTree = "<group>";
};
E521689629955E6800F366EF /* Resources */ = {
isa = PBXGroup;
children = (
EC7C1FED2987B252001DCE8B /* Assets.xcassets */,
);
path = Resources;
sourceTree = "<group>";
};
EC7C1FDD2987B251001DCE8B = {
isa = PBXGroup;
children = (
Expand All @@ -66,10 +96,9 @@
isa = PBXGroup;
children = (
EC7C2021298A70E7001DCE8B /* View */,
EC7C201C298A6AB4001DCE8B /* Input */,
EC7C20152987F458001DCE8B /* State */,
EC7C1FE92987B251001DCE8B /* iosSampleApp.swift */,
EC7C1FED2987B252001DCE8B /* Assets.xcassets */,
E521689529955E5600F366EF /* Application */,
E521689629955E6800F366EF /* Resources */,
EC7C1FEF2987B252001DCE8B /* Preview Content */,
);
path = iosSample;
Expand All @@ -91,19 +120,11 @@
path = State;
sourceTree = "<group>";
};
EC7C201C298A6AB4001DCE8B /* Input */ = {
isa = PBXGroup;
children = (
EC7C201A298A6A66001DCE8B /* VisualFormatter.swift */,
EC7C201D298A6AD1001DCE8B /* VisualExtentions.swift */,
);
path = Input;
sourceTree = "<group>";
};
EC7C2021298A70E7001DCE8B /* View */ = {
isa = PBXGroup;
children = (
EC7C201F298A6B76001DCE8B /* SecureTextFieldWithControl.swift */,
E521689429955E2100F366EF /* Extensions */,
E521688F29955B0E00F366EF /* ViewModifiers */,
EC7C1FEB2987B251001DCE8B /* TextFieldWithControl.swift */,
EC7C2022298A710B001DCE8B /* ToggleView.swift */,
EC7C2024298A7883001DCE8B /* SubmitButtonView.swift */,
Expand Down Expand Up @@ -204,13 +225,12 @@
buildActionMask = 2147483647;
files = (
EC7C2023298A710B001DCE8B /* ToggleView.swift in Sources */,
EC7C201B298A6A67001DCE8B /* VisualFormatter.swift in Sources */,
EC7C1FEC2987B251001DCE8B /* TextFieldWithControl.swift in Sources */,
EC7C2025298A7883001DCE8B /* SubmitButtonView.swift in Sources */,
EC7C20172987F483001DCE8B /* UnsafeObservableState.swift in Sources */,
EC7C2020298A6B76001DCE8B /* SecureTextFieldWithControl.swift in Sources */,
ECB57B3B298CFC4E00AE547C /* FormView.swift in Sources */,
EC7C201E298A6AD1001DCE8B /* VisualExtentions.swift in Sources */,
E521689129955B3F00F366EF /* ScrolledFocusField.swift in Sources */,
EC7C1FEA2987B251001DCE8B /* iosSampleApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -340,6 +360,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"iosSample/Preview Content\"";
DEVELOPMENT_TEAM = 4778UMCE49;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../sharedSample/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
GENERATE_INFOPLIST_FILE = YES;
Expand Down Expand Up @@ -374,6 +395,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"iosSample/Preview Content\"";
DEVELOPMENT_TEAM = 4778UMCE49;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../sharedSample/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)";
GENERATE_INFOPLIST_FILE = YES;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import sharedSample

@main
struct iosSampleApp: App {

@StateObject
private var rootHolder = RootHolder()
@StateObject private var rootHolder = RootHolder()

var body: some Scene {
WindowGroup {
Expand All @@ -16,7 +14,7 @@ struct iosSampleApp: App {
}
}

private class RootHolder : ObservableObject {
private final class RootHolder : ObservableObject {
let lifecycle: LifecycleRegistry
let formComponent: FormComponent

Expand Down
64 changes: 0 additions & 64 deletions sample/iosSample/iosSample/Input/VisualExtentions.swift

This file was deleted.

31 changes: 0 additions & 31 deletions sample/iosSample/iosSample/Input/VisualFormatter.swift

This file was deleted.

14 changes: 8 additions & 6 deletions sample/iosSample/iosSample/State/UnsafeObservableState.swift
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import Foundation
import sharedSample

public class UnsafeObservableState<T: AnyObject>: ObservableObject {

@Published
var value: T?
public final class UnsafeObservableState<T: AnyObject>: ObservableObject {
@Published var value: T?

private var cancelable: Cancelable? = nil

init(_ state: Kotlinx_coroutines_coreStateFlow) {
self.value = state.value as? T

cancelable = FlowWrapper<T>(flow: state).collect(consumer: { value in
cancelable = FlowWrapper<T>(flow: state).collect { value in
self.value = value
})
}
}

func reemitValue() {
value = value
}

deinit {
Expand Down
Loading