Showing a dynamic List in SwiftUi using data models from kotlin via kotlin multiplatform

74 Views Asked by At

I am currently building a mobile app with Kotlin Multiplatform and i'm stuck at the addressbook. I build a data model and the Backend / Database Calls in the shared module of Kotlin (Code below) and i'm trying to build the UI around it in SwiftUI. This is how it looks like: View:

import SwiftUI
import shared

//ToDo put in seperate class and call on it from Address Book
struct ContentRow: View {
    @Binding var item: Connection

    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                Image(uiImage: UIImage(systemName: item.userProfilePictureLink!)!)
                    .frame(width: 50, height: 50)
                VStack(alignment: .leading) {
                    Text(item.name!)
                        .font(.headline)
                }
            }
        }
    }
}

struct AddressBookView: View {
    @ObservedObject var viewModel = AddressBookViewModel()

    var body: some View {
        NavigationView {
            List {
                ForEach($viewModel.connection, id: \.userId) { connection in
                    NavigationLink(destination: PublicProfileView(username: connection.name?, profileimage: connection.userProfilePictureLink?)) {
                           ContentRow(item: connection)
                       }
                }
            }.navigationTitle("Contacts").navigationBarTitleDisplayMode(.inline)
        }.onAppear {
            Task.init {
                try await viewModel.fetchContacts()
            }
        }
    }
}

#Preview{
    AddressBookView()
}

i use this function to retrieve the data:

func fetchContacts() async throws {
        do { self.connection = try await GetCurrentUserContactsUseCase().execute() } catch {print("something happened \(error)")}
    }

and this is the data model used:

@Serializable
data class Connection(
    @SerialName("connectionId")
    var connectionId: String? = null,

    @SerialName("userId")
    var userId: String? = null,

    @SerialName("name")
    var name: String? = null,

    @SerialName("userProfilePictureLink")
    var userProfilePictureLink: String? = null,

    @SerialName("status")
    var status: String? = null,
)

I know that i should implement a wrapper for the call with appropriate error handling but for now i would be happy if it works in general. Anyway, with this code i get the following error message:

Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs)

What am i doing wrong here and can anyone point me in the right direction? I have another feature that i have to build in a similar matter so i would pretty much just have to copy what i do here. Thanks in Advance!

1

There are 1 best solutions below

2
workingdog support Ukraine On

There are a number of issues with your code. In your AddressBookView use @StateObject var viewModel = AddressBookViewModel() and use NavigationStack and do not use any ! in your code. Also do not use ?, but use $ for bindings, as shown in the example code:

Try this example code, assuming you have declared struct Connection: Identifiable {...} etc...

struct AddressBookView: View {
    @StateObject var viewModel = AddressBookViewModel() // <--- here

    var body: some View {
        NavigationStack {
            List {
                ForEach($viewModel.connection, id: \.userId) { $connection in // <--- here $
                    NavigationLink(destination: PublicProfileView(username: connection.name, profileimage: connection.userProfilePictureLink)) { // <--- here no ?
                           ContentRow(item: $connection) // <--- here $
                       }
                }
            }
            .navigationTitle("Contacts")
            .navigationBarTitleDisplayMode(.inline)
        }
        .task {
            do {
                try await viewModel.fetchContacts()  // <--- here
            } catch {
                print(error)
            }
        }
    }
}