chore: make favorite and hashtag scene use next page token from response header
This commit is contained in:
parent
0c8134463f
commit
ba48adb470
|
@ -35,6 +35,8 @@ extension HashtagTimelineViewModel.LoadOldestState {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Loading: HashtagTimelineViewModel.LoadOldestState {
|
class Loading: HashtagTimelineViewModel.LoadOldestState {
|
||||||
|
var maxID: String?
|
||||||
|
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Fail.self || stateClass == Idle.self || stateClass == NoMore.self
|
return stateClass == Fail.self || stateClass == Idle.self || stateClass == NoMore.self
|
||||||
}
|
}
|
||||||
|
@ -54,7 +56,7 @@ extension HashtagTimelineViewModel.LoadOldestState {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: only set large count when using Wi-Fi
|
// TODO: only set large count when using Wi-Fi
|
||||||
let maxID = last.id
|
let maxID = self.maxID ?? last.id
|
||||||
viewModel.context.apiService.hashtagTimeline(
|
viewModel.context.apiService.hashtagTimeline(
|
||||||
domain: activeMastodonAuthenticationBox.domain,
|
domain: activeMastodonAuthenticationBox.domain,
|
||||||
maxID: maxID,
|
maxID: maxID,
|
||||||
|
@ -71,10 +73,19 @@ extension HashtagTimelineViewModel.LoadOldestState {
|
||||||
// handle isFetchingLatestTimeline in fetch controller delegate
|
// handle isFetchingLatestTimeline in fetch controller delegate
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
} receiveValue: { response in
|
} receiveValue: { [weak self] response in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
let statuses = response.value
|
let statuses = response.value
|
||||||
// enter no more state when no new statuses
|
// enter no more state when no new statuses
|
||||||
if statuses.isEmpty || (statuses.count == 1 && statuses[0].id == maxID) {
|
|
||||||
|
let hasNextPage: Bool = {
|
||||||
|
guard let link = response.link else { return true } // assert has more when link invalid
|
||||||
|
return link.maxID != nil
|
||||||
|
}()
|
||||||
|
self.maxID = response.link?.maxID
|
||||||
|
|
||||||
|
if !hasNextPage || statuses.isEmpty || (statuses.count == 1 && statuses[0].id == maxID) {
|
||||||
stateMachine.enter(NoMore.self)
|
stateMachine.enter(NoMore.self)
|
||||||
} else {
|
} else {
|
||||||
stateMachine.enter(Idle.self)
|
stateMachine.enter(Idle.self)
|
||||||
|
|
|
@ -92,6 +92,9 @@ extension FavoriteViewModel.State {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Loading: FavoriteViewModel.State {
|
class Loading: FavoriteViewModel.State {
|
||||||
|
|
||||||
|
var maxID: String?
|
||||||
|
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
switch stateClass {
|
switch stateClass {
|
||||||
case is Fail.Type:
|
case is Fail.Type:
|
||||||
|
@ -113,8 +116,11 @@ extension FavoriteViewModel.State {
|
||||||
stateMachine.enter(Fail.self)
|
stateMachine.enter(Fail.self)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if previousState is Reloading {
|
||||||
let maxID = viewModel.statusFetchedResultsController.statusIDs.value.last
|
maxID = nil
|
||||||
|
}
|
||||||
|
// prefer use `maxID` token in response header
|
||||||
|
// let maxID = viewModel.statusFetchedResultsController.statusIDs.value.last
|
||||||
|
|
||||||
viewModel.context.apiService.favoritedStatuses(
|
viewModel.context.apiService.favoritedStatuses(
|
||||||
maxID: maxID,
|
maxID: maxID,
|
||||||
|
@ -139,8 +145,15 @@ extension FavoriteViewModel.State {
|
||||||
statusIDs.append(status.id)
|
statusIDs.append(status.id)
|
||||||
hasNewStatusesAppend = true
|
hasNewStatusesAppend = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.maxID = response.link?.maxID
|
||||||
|
|
||||||
|
let hasNextPage: Bool = {
|
||||||
|
guard let link = response.link else { return true } // assert has more when link invalid
|
||||||
|
return link.maxID != nil
|
||||||
|
}()
|
||||||
|
|
||||||
if hasNewStatusesAppend {
|
if hasNewStatusesAppend && hasNextPage {
|
||||||
stateMachine.enter(Idle.self)
|
stateMachine.enter(Idle.self)
|
||||||
} else {
|
} else {
|
||||||
stateMachine.enter(NoMore.self)
|
stateMachine.enter(NoMore.self)
|
||||||
|
|
|
@ -18,6 +18,7 @@ extension Mastodon.Response {
|
||||||
|
|
||||||
// application fields
|
// application fields
|
||||||
public let rateLimit: RateLimit?
|
public let rateLimit: RateLimit?
|
||||||
|
public let link: Link?
|
||||||
public let responseTime: Int?
|
public let responseTime: Int?
|
||||||
|
|
||||||
public var networkDate: Date {
|
public var networkDate: Date {
|
||||||
|
@ -33,6 +34,11 @@ extension Mastodon.Response {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
self.rateLimit = RateLimit(response: response)
|
self.rateLimit = RateLimit(response: response)
|
||||||
|
self.link = {
|
||||||
|
guard let string = (response as? HTTPURLResponse)?.value(forHTTPHeaderField: "link") else { return nil }
|
||||||
|
return Link(link: string)
|
||||||
|
}()
|
||||||
|
|
||||||
self.responseTime = {
|
self.responseTime = {
|
||||||
guard let string = (response as? HTTPURLResponse)?.value(forHTTPHeaderField: "x-response-time") else { return nil }
|
guard let string = (response as? HTTPURLResponse)?.value(forHTTPHeaderField: "x-response-time") else { return nil }
|
||||||
return Int(string)
|
return Int(string)
|
||||||
|
@ -43,6 +49,7 @@ extension Mastodon.Response {
|
||||||
self.value = value
|
self.value = value
|
||||||
self.date = old.date
|
self.date = old.date
|
||||||
self.rateLimit = old.rateLimit
|
self.rateLimit = old.rateLimit
|
||||||
|
self.link = old.link
|
||||||
self.responseTime = old.responseTime
|
self.responseTime = old.responseTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,3 +97,30 @@ extension Mastodon.Response {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Mastodon.Response {
|
||||||
|
public struct Link {
|
||||||
|
public let maxID: Mastodon.Entity.Status.ID?
|
||||||
|
public let minID: Mastodon.Entity.Status.ID?
|
||||||
|
|
||||||
|
init(link: String) {
|
||||||
|
self.maxID = {
|
||||||
|
guard let regex = try? NSRegularExpression(pattern: "max_id=([[:digit:]]+)", options: []) else { return nil }
|
||||||
|
let results = regex.matches(in: link, options: [], range: NSRange(link.startIndex..<link.endIndex, in: link))
|
||||||
|
guard let match = results.first else { return nil }
|
||||||
|
guard let range = Range(match.range(at: 1), in: link) else { return nil }
|
||||||
|
let id = link[range]
|
||||||
|
return String(id)
|
||||||
|
}()
|
||||||
|
|
||||||
|
self.minID = {
|
||||||
|
guard let regex = try? NSRegularExpression(pattern: "min_id=([[:digit:]]+)", options: []) else { return nil }
|
||||||
|
let results = regex.matches(in: link, options: [], range: NSRange(link.startIndex..<link.endIndex, in: link))
|
||||||
|
guard let match = results.first else { return nil }
|
||||||
|
guard let range = Range(match.range(at: 1), in: link) else { return nil }
|
||||||
|
let id = link[range]
|
||||||
|
return String(id)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue