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

Is it possible to use interfaces of ViewModel in Swift? #244

Open
olegivo opened this issue Jun 14, 2023 · 1 comment
Open

Is it possible to use interfaces of ViewModel in Swift? #244

olegivo opened this issue Jun 14, 2023 · 1 comment

Comments

@olegivo
Copy link

olegivo commented Jun 14, 2023

Interfaces are useful in case of faking in previews.
For example:

interface ItemViewModel {
    val title: CMutableStateFlow<String>
    val isEditing: CStateFlow<Boolean>
    val canSave: CStateFlow<Boolean>
}

class ItemViewModelImpl(
    private val heavyDependency1: HeavyDependency1,
    private val heavyDependency2: HeavyDependency2,
    ...
    private val heavyDependency101: HeavyDependency101,
): ViewModel(), ItemViewModel {
    override val title = MutableStateFlow("").cMutableStateFlow()
    override val isEditing = MutableStateFlow(false).cMutableStateFlow()
    override val canSave = MutableStateFlow(false).cMutableStateFlow()
}

class ItemViewModelFake(
    title: String,
    isEditing: Boolean = false,
    canSave: Boolean = false,
): ViewModel(), ItemViewModel {
    override val title = MutableStateFlow(title).cMutableStateFlow()
    override val isEditing = MutableStateFlow(isEditing).cStateFlow()
    override val canSave = MutableStateFlow(canSave).cStateFlow()
}

@Composable
fun Item(viewModel: ViewModel /*for the sake of simplicity without DI*/) {
    // some UI
}

And use them for previews:

@Preview
@Composable
private fun ItemPreview() {
    MaterialTheme {
        Item(
            ViewModelFake(title = "123")
        )
    }
}

@Preview
@Composable
private fun ItemEditingCannotSavePreview() {
    MaterialTheme {
        Item(
            ViewModelFake(title = "123", isEditing = true)
        )
    }
}

@Preview
@Composable
private fun ItemEditingCanSavePreview() {
    MaterialTheme {
        Item(
            ViewModelFake(title = "123", isEditing = true, canSave = true)
        )
    }
}

But not for SwiftUI. We can't make extensions for protocols (to be ObservableObject).

@darronschall
Copy link
Contributor

You can support this in SwiftUI with generics. Something like this (apologies if this doesn't compile, writhing this code directly in a comment):

struct ItemView<Model>: View where Model: ItemViewModel & ViewModel {
    @ObservedObject var viewModel: Model

    var body: some View {
       Text(viewModel.state(\.title))
    }
}

struct ItemView_Previews: PreviewProvider {
    static var previews: some View {
        ItemView<ItemViewModelFake>(
            viewModel: ItemViewModelFake()
        )
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants