Closed JulesBer closed 5 months ago
One alternative at least is to use something like SKIE (https://skie.touchlab.co/features/flows). That's what I'm using in https://github.com/joreilly/FantasyPremierLeague
I am using SKIE
Here is what my viewmodel and swiftui view look like if it can help
open class VehiclesListViewModel : ViewModel(), KoinComponent {
private val vehiclesRepository: VehiclesRepository by inject()
private val appPreferencesRepository: AppPreferencesRepository by inject()
companion object {
const val POS_KEYWORD = "pointOfSales[]"
}
private val viewModelState = MutableStateFlow<PagingData<Vehicle>>(PagingData.empty())
val uiState = viewModelState.asStateFlow()
private val vehiclesPagingDataPresenter = object : PagingDataPresenter<Vehicle>() {
override suspend fun presentPagingDataEvent(event: PagingDataEvent<Vehicle>) {
print(event)
updateVehiclesSnapshotList()
}
}
val vehiclesSnapshotList: MutableStateFlow<ItemSnapshotList<Vehicle>> = MutableStateFlow<ItemSnapshotList<Vehicle>>(
vehiclesPagingDataPresenter.snapshot()
)
private fun updateVehiclesSnapshotList() {
vehiclesSnapshotList.value = vehiclesPagingDataPresenter.snapshot()
}
fun getElement(index: Int): Vehicle? {
return vehiclesPagingDataPresenter.get(index)
}
fun init() {
viewModelScope.launch {
//getVehicles(initFilters)
uiState.collectLatest {
vehiclesPagingDataPresenter.collectFrom(it)
}
}
}
}
import SwiftUI
import shared
struct VehiclesView: View {
@EnvironmentObject var themeManager: ThemeManager
@State var viewModel: VehiclesListViewModel
init() {
viewModel = VehiclesListViewModel()
viewModel.doInit()
}
var body: some View {
List {
let _ = print(viewModel.vehiclesSnapshotList.value)
ForEach(viewModel.vehiclesSnapshotList.value.indices, id: \.self) { index in
if let vehicle = viewModel.getElement(index: Int32(index)) {
Text("\(vehicle.make) \(vehicle.model)")
}
}
}
}
}
I found a way to update the view using touchlab SKIE and updating a state that i added in my viewmodel
my view is now like this
List {
if (vehicleListScreenState is VehicleListScreenStateFirstLoading) {
ProgressView()
} else {
ForEach(vehicles.indices, id: \.self) { index in
if let vehicle = viewModel.getElement(index: Int32(index)) {
Text("\(vehicle.make) \(vehicle.model)")
}
}
}
}
.padding(.bottom, themeManager.selectedTheme.mediumPadding)
.listStyle(.plain)
.task {
for await state in viewModel.vehicleListScreenState {
print(state)
self.vehicleListScreenState = state
}
}
viewModel.vehicleListScreenState is update by using the pagingDataPresenter.addLoadStateListener
Hi @JulesBer could you share your full implementation. I have an issue like yours. After ending the first page the second page is not loaded in my project(I mean just about iOS side) . I use KMP-ObservableViewModel. And implemented everything as like as @joreilly ''s example
Hello,
I am trying to implement a paged infinite scroll view just like you did in this project. However I use the new multiplatform androidx lifecycle viewmodel. My problem is that my switfui view isn't update when I receive the new data. Do you know if it is possible to implement the same view as you, without using the KMP-ObservableViewModel lib ?