https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
m

Marc

10/08/2023, 9:00 AM
Are there any known problems with Kotlin Objects in Swift? I used one for my SubmitLogin event and it does not seem to be called in my kotlin viewmodel. I think, this is maybe because it is defines as an object in kotlin, as the ChangeUsername- and ChangePasswordText events are working properly
m

mohamed rejeb

10/08/2023, 11:00 AM
can you share your onEvent method, how you are checking for the events
m

Marc

10/08/2023, 11:04 AM
Copy code
fun onEvent(event: LoginEvent) {
        when (event) {
            is LoginEvent.ChangePasswordText -> _state.update { it.copy(
                passwordText = event.password
            ) }

            is LoginEvent.ChangeUsernameText -> _state.update { it.copy(
                usernameText = event.username
            ) }

            is LoginEvent.TogglePasswordVisibility -> _state.update { it.copy(
                isPasswordVisible = !it.isPasswordVisible
            ) }

            is LoginEvent.SubmitLogin -> login(_state.value)

            is LoginEvent.DismissErrorBox -> _state.update { it.copy(
                isError = false
            ) }
        }
    }
m

mohamed rejeb

10/08/2023, 11:06 AM
Does changing the object to data object solves the problem?
m

Marc

10/08/2023, 11:07 AM
Copy code
extension LoginScreen {
    
    @MainActor class IOSLoginViewModel: ObservableObject {
        
        private let viewModel: LoginViewModel
        
        @Published var state: LoginState = LoginState(
            usernameText: "",
            passwordText: "",
            isError: false,
            isLoading: false,
            isPasswordVisible: false,
            isAuthenticated: false
        )
        
        private var handle: DisposableHandle?
        
        init(userAuthApi: UserAuthApi) {
            self.viewModel = LoginViewModel(
                userAuthApi: userAuthApi,
                coroutineScope: nil
            )
        }
        
        func onEvent(event: LoginEvent) {
            viewModel.onEvent(event: event)
        }
        
        func startObserving() {
            handle = viewModel.state.subscribe(onCollect: { state in
                if let state = state {
                    self.state = state
                }
            })
        }
                
        func dispose() {
            handle?.dispose()
        }
        
    }
    
}
This is my IOS ViewModel btw
m

mohamed rejeb

10/08/2023, 11:08 AM
Everything looks good for me, I thought that you are not using
is
to check the objects
m

Marc

10/08/2023, 11:09 AM
Okey
This is the way, I use the passwordtext state. Maybe there's something wrong with it
Copy code
SecureField(
                    text: Binding(get: { viewModel.state.passwordText }, set: { value in
                        viewModel.onEvent(event: .ChangePasswordText(password: value))
                    }),
                    label: {
                        Text("Passwort")
                    }
                )
                .padding()
                .background(Color(.systemGray6))
                .clipShape(RoundedRectangle(cornerRadius: 5.0))
                .padding(.bottom)
                .textContentType(.password)
Change to data object did not work
This is my whole LoginScreen
Copy code
struct LoginScreen: View {
    
    @ObservedObject var viewModel: IOSLoginViewModel
    
    init(userAuthApi: UserAuthApi) {
        self.viewModel = IOSLoginViewModel(userAuthApi: userAuthApi)
    }
    
    var body: some View {
        ZStack {
            VStack(alignment: .center) {                
                TextField(
                    "Benutzername",
                    text: Binding(get: { viewModel.state.usernameText }, set: { value in
                        viewModel.onEvent(event: .ChangeUsernameText(username: value))
                    })
                )
                .padding()
                .background(Color(.systemGray6))
                .clipShape(RoundedRectangle(cornerRadius: 5.0))
                .textContentType(.username)
                            
                SecureField(
                    text: Binding(get: { viewModel.state.passwordText }, set: { value in
                        viewModel.onEvent(event: .ChangePasswordText(password: value))
                    }),
                    label: {
                        Text("Passwort")
                    }
                )
                .padding()
                .background(Color(.systemGray6))
                .clipShape(RoundedRectangle(cornerRadius: 5.0))
                .padding(.bottom)
                .textContentType(.password)
                  
                
                HStack {
                    Button("Login", action: {
                        viewModel.onEvent(event: .SubmitLogin())
                    })
                    .padding()
                    .frame(width: .defaultWidth / 2, height: .defaultHeight)
                    .background(.blue)
                    .foregroundColor(.primary)
                    .clipShape(RoundedRectangle(cornerRadius: 5.0))
                }
                .frame(
                    maxWidth: .infinity,
                    alignment: .leading
                )
        
                
            }
            .padding()
            .onAppear() {
                viewModel.startObserving()
            }
            .onDisappear() {
                viewModel.dispose()
        }
        }
    }
}

struct LoginScreen_Previews: PreviewProvider {
    static var previews: some View {
        LoginScreen(userAuthApi: AppModule().userAuthApi)
    }
}
s

streetsofboston

10/08/2023, 12:47 PM
An
object
is accessed through a static/shared reference: https://kotlinlang.org/docs/native-objc-interop.html#kotlin-singletons Try adding the
.shared
property and see if that works
m

Marc

10/08/2023, 12:51 PM
Bildschirmfoto 2023-10-08 um 14.51.22.png
s

streetsofboston

10/08/2023, 12:52 PM
.... SubmitLogin.shared
m

Marc

10/08/2023, 12:55 PM
It still does not fire the event. The login function should set the passwordText back to ""
Bildschirmfoto 2023-10-08 um 14.55.23.png
Only thing, i could imagine is that the null check does not work properly
might also be relevant information
v

Viktor Nyblom

10/09/2023, 1:39 AM
From what I can see you don't set
usernameText
and
passwordText
to
""
, like you say you want to. In the last statement you copy the previous value, including the previous
usernameText
and
passwordText
.
m

Marc

10/09/2023, 3:10 AM
here i change the passwordText, in case, the User returned by the api is null
v

Viktor Nyblom

10/09/2023, 3:27 AM
Ah right! I though you meant they should be reset if the user is successfully logged in. 😃 Then I have no idea. I would probably just set a bunch of break points and logs to see what's actually happening.
m

Marc

10/09/2023, 4:30 AM
Yesterday, I added a log to the oberver in the viewModel to see when Swift recieves a state update. Seemed not to be called on login
n

Nicolas Picon

10/09/2023, 5:06 AM
If
SubmitLogin
is an object, is there a constructor to invoke? Try with
viewModel.onEvent(event: LoginEvent.SubmitLogin)
m

Marc

10/09/2023, 6:05 AM
Copy code
viewModel.onEvent(event: .SubmitLogin.shared)
I tried it with that
regarding to this message
Problem was, that I've used the coroutineScope instead of the viewModelScope variable 🤦‍♂️