I have 2 different endpoint:
- The first one have a pagination.
- The second one doesn't have pagination
I mapping the object from the first and second endpoint so they have the same object when i display it and limit only 10 item.
The Question is.. Is that possible to combine the API called so i can use pagination with different endpoint? so the result is
- Merge the object into 1
- Sort by date
- Limit the item only 10 item
So far i can't figure it out how to combine an API, this is my service setup
func getMessageList(page: Int) -> Single<[Message]> {
return platformBanking.getMessageList(token: sessionStore.token, page: page, pageSize: 10)
}
func getMoInbox() -> Single<[Message]> {
return Single.create { single in
MOInbox.sharedInstance.getInboxMessages { inboxMessages, accountMeta in
var messages: [Message] = []
inboxMessages.forEach { entry in
let message: Message = .init()
message.title = entry.notificationTitle
message.subtitle = entry.notificationSubTitle
message.body = entry.notificationBody
message.messageType = !(entry.campaignID?.isEmpty ?? false) ? 5 : 1
message.imageName = entry.notificationMediaURL ?? ""
message.date = entry.receivedDate?.string(withFormat: "dd MMM") ?? ""
message.isRead = entry.isRead
message.action = entry.deepLinkURL ?? ""
messages.append(message)
}
single(.success(messages))
}
return Disposables.create()
}
}
This is in my ViewModel
var filterMessages: [Message] = []
private var page: Int = 1
private var isLoading: Bool = false
private var endOfMessage: Bool = false
private func getMessageInboxList() {
var inboxMessages: [Message] = []
isLoading = true
Single.zip(manageMessages.getMessageList(page: page), manageMessages.getMoInbox())
.subscribe(onSuccess: { [weak self] firstMessage, secondMessage in
inboxMessages.append(contentsOf: firstMessage)
inboxMessages.append(contentsOf: secondMessage)
self?.processMessages(messages: inboxMessages)
}).disposed(by: disposedBag)
}
private func processMessages(messages: [Message]) {
self.messages.append(contentsOf: messages)
self.filterMessages = self.messages.sorted(by: { $0.date > $1.date })
eventShowHideLoadingIndicator.onNext(false)
if messages.count < 10 {
endOfMessage = true
}
eventMessagesDataUpdated.onNext(())
isLoading = false
}
This is a function to called pagination in viewModel, when i try paginate i just realize i make a duplicate item from getMoInbox API called. but still combining the object and limiting by 10 item i still can't find the answer.
func loadMoreMessageInbox() {
guard !endOfMessage, !isLoading, selectedIndex == 0 else { return }
page = page 1
getMessageInboxList()
}
Please help me guys.
CodePudding user response:
This requires a state machine. There are a number of different libraries that you could use (a partial list is at the bottom.)
Here is an example using the cycle
function from my library.
enum Input {
case nextPageRequested // emit this to `input` when you are ready for the next page.
case pageReceived(Int, [Message]) // this is emitted with the page results.
}
struct State<T> {
var pages: [Int: [T]] = [:] // stores the pages as they come in. The MoMessages will be stored in page 0
}
func example(input: Observable<Input>, messageManager: MessageManager) -> Observable<[Message]> {
Single.zip(messageManager.getMoInbox(), messageManager.getMessageList(page: 1))
.asObservable()
.flatMap { moMessages, page1Messages in
// create state machine initialized with the moMessages and page1Messages
cycle(
input: input,
initialState: State(pages: [0: moMessages, 1: page1Messages]),
reduce: { state, input in
// when a new page is received, store it
if case let .pageReceived(page, messages) = input {
state.pages[page] = messages
}
},
reaction: reaction(
request: { state, input in
// when a new page is requested, figure out what page number you need and return it (otherwise return nil)
guard case .nextPageRequested = input else { return nil }
return state.pages.keys.max() 1
},
effect: { page in
// get the page you need
messageManager.getMessageList(page: page)
.map { Input.pageReceived(page, $0) }
.asObservable()
}
)
)
}
.map { state in
// sort the messages in the pages and return them
state.pages.values.flatMap { $0 }.sorted(by: { $0.date > $1.date })
}
}
Here's that promised list: