Imagine the following scenario: ```struct SampleUI...
# compose-ios
g
Imagine the following scenario:
Copy code
struct SampleUIViewController: UIViewControllerRepresentable {
    
    @Binding var status: String
    let action: () -> Void
    
    func makeUIViewController(context: Context) -> UIViewController {
        return SharedViewControllers().SampleComposable(status: status, click: action)
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) { 
         //how to update the composable state when binding values changes?
    }
}

struct ComposeScreen: View {
    
    @StateObject private var viewModel = ViewModels.sampleViewModel()
    @State private var status: String = ""
    
    var body: some View {
        SampleUIViewController(
            status: $status,
            action: { viewModel.doSomething() }
        )
        .onReceive(viewModel.$state) { new in            
            status = new.label()
        }
        .ignoresSafeArea()
    }
}
I know from logging that the ViewModel state emission is working (also the
viewModel.doSomething()
) and reaching iOS. If I’m using SwiftUi this updates de View, but now on Compose (probably because we’re using a generic ViewController?) this is not updating my screen. How can I solve this? We must have the possibility to use the
updateUIViewController
.
👍 1
d
It is very interesting question. We don't provide solution of this situation yet. For now you can pass data throw the external objects outside of SwiftUI hierarchy. You can take a look at our sample here: https://github.com/JetBrains/compose-multiplatform/tree/master/examples/chat
g
I’ve open and issue https://github.com/JetBrains/compose-multiplatform/issues/3478 because I believe it’s a very interesting use-case, principally if we want to welcome iOS developers and incremental adoption. Also, it adds the possibility in a project not sharing ViewModels to share Composables without going all in with Composable + ViewModel share.
Actually, I had already found your example and studied it. 🙂 However, I didn’t quite understand how you’re able to send data to the “composable” through it, allowing it to react and readjust.
ooh is it here? 🤔
Currently, I employ a shared module where the ViewModel is accessible, and state is generated through a state machine. Each platform then utilizes this ViewModel, implementing its unique UI. This setup is functioning well. Indeed, since I’m already sharing the ViewModel, extending this concept to include both UI and ViewModel sharing could be feasible. My POC involves testing two separate modules: one for sharing the VM and another for sharing the UI. This configuration offers the flexibility of: 1. Employing the same VM across all platforms with differing UI frameworks. 2. Utilising a consistent VM and UI framework across all platforms. While keeping in mind the shared VM, I’d also like to retain the option for each platform to manage its UI State using its respective VMs. From your explanation, it seems your approach involves utilising a Flow, effectively acting as a “VM,” to share the Composable State. Instead of altering the Composable directly within the iOSApp, you emit a state change to that Flow in the commonMain, making it change the composable internally. Am I correct in understanding this? Apologies if my previous message was unclear! 😅
@Dima Avdeev made it work by:
Copy code
object SharedViewControllers {

    private data class ComposeUIViewState(val status: String = "")
    private val _state = MutableStateFlow(ComposeUIViewState())

    fun sampleComposable(status: String, click: () -> Unit): UIViewController {
        return ComposeUIViewController {
            with(_state.collectAsState().value) {
                 Composable(state.status, click)
            }
        }
    }

    fun updateSampleComposable(status: String) {
        _state.update { ComposeUIViewState(status = status) }
    }
}
Copy code
struct SampleUIViewController: UIViewControllerRepresentable {
    
    @Binding var status: String
    let action: () -> Void
    
    func makeUIViewController(context: Context) -> UIViewController {
        return SharedViewControllers().sampleComposable(click: action)
    }
    
    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
          SharedViewControllers().updateSampleComposable(status: status)
    }
}
Not very graceful though.
👍 1
d
Hey @Guilherme Delgado did that actually work? This could solve my post. I'll give it a shot soon. Thanks!
g