Skip to content
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

Ability to define a UIViewController type #3478

Open
GuilhE opened this issue Aug 10, 2023 · 10 comments
Open

Ability to define a UIViewController type #3478

GuilhE opened this issue Aug 10, 2023 · 10 comments
Assignees
Labels
discussion Need further discussion to understand if it actually needed enhancement New feature or request

Comments

@GuilhE
Copy link
Contributor

GuilhE commented Aug 10, 2023

The absence of a specific type for androidx.compose.ui.window.ComposeUIViewControllerand platform.UIKit.UIViewController presents a limitation in using updateUIViewController and, consequently, the associated Composable.

In scenarios where the iOS application requires management of Composable state through an iOS ViewModel, the availability of such types would prove to be advantageous:

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 find this use-case quite intriguing, particularly in its potential to attract iOS developers and facilitate incremental adoption. Furthermore, it introduces the exciting possibility of incorporating Composables into a project without the necessity of sharing ViewModels. This offers a more flexible approach compared to a full-fledged Composable + ViewModel sharing strategy.

Currently, the workaround I've discovered involves incorporating a MutableStateFlow within the ComposeUIViewController, which responds to changes in state properties:

object SharedViewControllers {

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

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

    fun updateSampleComposable(status: String) {
        state.update { ComposeUIViewState(status = status) }
    }
}

on iosApp side:

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)
    }
}

It works, but it's not very graceful.

@GuilhE GuilhE added enhancement New feature or request submitted labels Aug 10, 2023
@elijah-semyonov elijah-semyonov added discussion Need further discussion to understand if it actually needed and removed submitted labels Aug 11, 2023
@elijah-semyonov
Copy link
Contributor

elijah-semyonov commented Aug 11, 2023

Thanks for the report. We are currently iterating on API design and real usage examples like this are quite useful.

@GuilhE
Copy link
Contributor Author

GuilhE commented Aug 11, 2023

Thanks for the report. We are currently iterating on API design and real usage examples like this are quite useful.

Hello @elijah-semyonov, you can find here a working sample 😉

@elijah-semyonov
Copy link
Contributor

elijah-semyonov commented Aug 30, 2023

@GuilhE
What's currently preventing you from using Kotlin Objective-C object (a ViewModel basically), storing MutableState which could be changed inside update method? In this case your setContent could simply reference this object and this mutable state and execute differently based on its value.

@GuilhE
Copy link
Contributor Author

GuilhE commented Aug 30, 2023

@GuilhE What's currently preventing you from using Kotlin Objective-C object (a ViewModel basically), storing MutableState which could be changed inside update method? In this case your setContent could simply reference this object and this mutable state and execute differently based on its value.

I believe that's the work around I'm using, basically I've a Singleton with a Flow/mutableState that the iosApp can call to update the state. The ComposeUIViewController observes this Flow/mutableState and changes accordingly.

@elijah-semyonov
Copy link
Contributor

We are drifting toward a design, where the state is managed outside of ComposeWindow for multiple reasons (scene destruction on removal from window hierarchy, for example). So it feels like a proper way to do and not just workaround.

@dima-avdeev-jb dima-avdeev-jb self-assigned this Aug 31, 2023
@dima-avdeev-jb
Copy link
Contributor

@dima-avdeev-jb
Copy link
Contributor

We will discuss it. And try to make better solution for all your needs. But it will take some time.

@GuilhE
Copy link
Contributor Author

GuilhE commented Aug 31, 2023

Thanks for your work guys and for letting the community help! 🙏🏼

@GuilhE
Copy link
Contributor Author

GuilhE commented Sep 6, 2023

This might come in handy 😇
https://github.com/GuilhE/KMP-ComposeUIViewController

@GuilhE
Copy link
Contributor Author

GuilhE commented Sep 8, 2023

@elijah-semyonov @dima-avdeev-jb latest release changelog:

[1.1.0-ALPHA]
- Adds capability to generate .swift files with UIViewControllerRepresentables.
- Adds script to include those generated files into xcodeproj to be accessible in iOS project;

😇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion Need further discussion to understand if it actually needed enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants