mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-02-18 10:45:15 +00:00
Prepend new timeline statuses and new notifications
This commit is contained in:
parent
bbab8981f3
commit
569aedeaeb
8 changed files with 59 additions and 37 deletions
|
@ -4,3 +4,14 @@ public protocol Endpoint {
|
||||||
func path() -> String
|
func path() -> String
|
||||||
func queryItems() -> [URLQueryItem]?
|
func queryItems() -> [URLQueryItem]?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Endpoint {
|
||||||
|
func makePaginationParam(sinceId: String?, maxId: String?) -> [URLQueryItem]? {
|
||||||
|
if let sinceId {
|
||||||
|
return [.init(name: "since_id", value: sinceId)]
|
||||||
|
} else if let maxId {
|
||||||
|
return [.init(name: "max_id", value: maxId)]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum Notifications: Endpoint {
|
public enum Notifications: Endpoint {
|
||||||
case notifications(maxId: String?, onlyMentions: Bool)
|
case notifications(sinceId: String?,
|
||||||
|
maxId: String?,
|
||||||
|
types: [String]?)
|
||||||
|
|
||||||
public func path() -> String {
|
public func path() -> String {
|
||||||
switch self {
|
switch self {
|
||||||
|
@ -12,13 +14,12 @@ public enum Notifications: Endpoint {
|
||||||
|
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case .notifications(let maxId, let onlyMentions):
|
case .notifications(let sinceId, let maxId, let types):
|
||||||
var params: [URLQueryItem] = []
|
var params = makePaginationParam(sinceId: sinceId, maxId: maxId) ?? []
|
||||||
if onlyMentions {
|
if let types {
|
||||||
params.append(.init(name: "types[]", value: "mention"))
|
for type in types {
|
||||||
|
params.append(.init(name: "types[]", value: type))
|
||||||
}
|
}
|
||||||
if let maxId {
|
|
||||||
params.append(.init(name: "max_id", value: maxId))
|
|
||||||
}
|
}
|
||||||
return params
|
return params
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public enum Timelines: Endpoint {
|
public enum Timelines: Endpoint {
|
||||||
case pub(sinceId: String?)
|
case pub(sinceId: String?, maxId: String?)
|
||||||
case home(sinceId: String?)
|
case home(sinceId: String?, maxId: String?)
|
||||||
case hashtag(tag: String, sinceId: String?)
|
case hashtag(tag: String, maxId: String?)
|
||||||
|
|
||||||
public func path() -> String {
|
public func path() -> String {
|
||||||
switch self {
|
switch self {
|
||||||
|
@ -18,15 +18,12 @@ public enum Timelines: Endpoint {
|
||||||
|
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case .pub(let sinceId):
|
case .pub(let sinceId, let maxId):
|
||||||
guard let sinceId else { return nil }
|
return makePaginationParam(sinceId: sinceId, maxId: maxId)
|
||||||
return [.init(name: "max_id", value: sinceId)]
|
case .home(let sinceId, let maxId):
|
||||||
case .home(let sinceId):
|
return makePaginationParam(sinceId: sinceId, maxId: maxId)
|
||||||
guard let sinceId else { return nil }
|
case let .hashtag(_, maxId):
|
||||||
return [.init(name: "max_id", value: sinceId)]
|
return makePaginationParam(sinceId: nil, maxId: maxId)
|
||||||
case let .hashtag(_, sinceId):
|
|
||||||
guard let sinceId else { return nil }
|
|
||||||
return [.init(name: "max_id", value: sinceId)]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,10 +37,8 @@ public struct NotificationsListView: View {
|
||||||
await viewModel.fetchNotifications()
|
await viewModel.fetchNotifications()
|
||||||
}
|
}
|
||||||
.refreshable {
|
.refreshable {
|
||||||
Task {
|
|
||||||
await viewModel.fetchNotifications()
|
await viewModel.fetchNotifications()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.navigationTitle(Text("Notifications"))
|
.navigationTitle(Text("Notifications"))
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,25 @@ class NotificationsViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var notifications: [Models.Notification] = []
|
private var notifications: [Models.Notification] = []
|
||||||
|
private var queryTypes: [String]? {
|
||||||
|
tab == .mentions ? ["mention"] : nil
|
||||||
|
}
|
||||||
|
|
||||||
func fetchNotifications() async {
|
func fetchNotifications() async {
|
||||||
guard let client else { return }
|
guard let client else { return }
|
||||||
do {
|
do {
|
||||||
if notifications.isEmpty {
|
if notifications.isEmpty {
|
||||||
state = .loading
|
state = .loading
|
||||||
|
notifications = try await client.get(endpoint: Notifications.notifications(sinceId: nil,
|
||||||
|
maxId: nil,
|
||||||
|
types: queryTypes))
|
||||||
|
} else if let first = notifications.first {
|
||||||
|
let newNotifications: [Models.Notification] =
|
||||||
|
try await client.get(endpoint: Notifications.notifications(sinceId: first.id,
|
||||||
|
maxId: nil,
|
||||||
|
types: queryTypes))
|
||||||
|
notifications.insert(contentsOf: newNotifications, at: 0)
|
||||||
}
|
}
|
||||||
notifications = try await client.get(endpoint: Notifications.notifications(maxId: nil,
|
|
||||||
onlyMentions: tab == .mentions))
|
|
||||||
state = .display(notifications: notifications, nextPageState: .hasNextPage)
|
state = .display(notifications: notifications, nextPageState: .hasNextPage)
|
||||||
} catch {
|
} catch {
|
||||||
state = .error(error: error)
|
state = .error(error: error)
|
||||||
|
@ -51,8 +61,10 @@ class NotificationsViewModel: ObservableObject {
|
||||||
do {
|
do {
|
||||||
guard let lastId = notifications.last?.id else { return }
|
guard let lastId = notifications.last?.id else { return }
|
||||||
state = .display(notifications: notifications, nextPageState: .loadingNextPage)
|
state = .display(notifications: notifications, nextPageState: .loadingNextPage)
|
||||||
let newNotifications: [Models.Notification] = try await client.get(endpoint: Notifications.notifications(maxId: lastId,
|
let newNotifications: [Models.Notification] =
|
||||||
onlyMentions: tab == .mentions))
|
try await client.get(endpoint: Notifications.notifications(sinceId: nil,
|
||||||
|
maxId: lastId,
|
||||||
|
types: queryTypes))
|
||||||
notifications.append(contentsOf: newNotifications)
|
notifications.append(contentsOf: newNotifications)
|
||||||
state = .display(notifications: notifications, nextPageState: .hasNextPage)
|
state = .display(notifications: notifications, nextPageState: .hasNextPage)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -25,15 +25,15 @@ public enum TimelineFilter: Hashable, Equatable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func endpoint(sinceId: String?) -> Endpoint {
|
func endpoint(sinceId: String?, maxId: String?) -> Endpoint {
|
||||||
switch self {
|
switch self {
|
||||||
case .pub: return Timelines.pub(sinceId: sinceId)
|
case .pub: return Timelines.pub(sinceId: sinceId, maxId: maxId)
|
||||||
case .home: return Timelines.home(sinceId: sinceId)
|
case .home: return Timelines.home(sinceId: sinceId, maxId: maxId)
|
||||||
case let .hashtag(tag, accountId):
|
case let .hashtag(tag, accountId):
|
||||||
if let accountId {
|
if let accountId {
|
||||||
return Accounts.statuses(id: accountId, sinceId: nil, tag: tag)
|
return Accounts.statuses(id: accountId, sinceId: nil, tag: tag)
|
||||||
} else {
|
} else {
|
||||||
return Timelines.hashtag(tag: tag, sinceId: sinceId)
|
return Timelines.hashtag(tag: tag, maxId: maxId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,9 @@ public struct TimelineView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.refreshable {
|
.refreshable {
|
||||||
Task {
|
|
||||||
await viewModel.fetchStatuses()
|
await viewModel.fetchStatuses()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var tagHeaderView: some View {
|
private var tagHeaderView: some View {
|
||||||
|
|
|
@ -34,8 +34,13 @@ class TimelineViewModel: ObservableObject, StatusesFetcher {
|
||||||
func fetchStatuses() async {
|
func fetchStatuses() async {
|
||||||
guard let client else { return }
|
guard let client else { return }
|
||||||
do {
|
do {
|
||||||
|
if statuses.isEmpty {
|
||||||
statusesState = .loading
|
statusesState = .loading
|
||||||
statuses = try await client.get(endpoint: timeline.endpoint(sinceId: nil))
|
statuses = try await client.get(endpoint: timeline.endpoint(sinceId: nil, maxId: nil))
|
||||||
|
} else if let first = statuses.first {
|
||||||
|
let newStatuses: [Status] = try await client.get(endpoint: timeline.endpoint(sinceId: first.id, maxId: nil))
|
||||||
|
statuses.insert(contentsOf: newStatuses, at: 0)
|
||||||
|
}
|
||||||
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
||||||
} catch {
|
} catch {
|
||||||
statusesState = .error(error: error)
|
statusesState = .error(error: error)
|
||||||
|
@ -48,7 +53,7 @@ class TimelineViewModel: ObservableObject, StatusesFetcher {
|
||||||
do {
|
do {
|
||||||
guard let lastId = statuses.last?.id else { return }
|
guard let lastId = statuses.last?.id else { return }
|
||||||
statusesState = .display(statuses: statuses, nextPageState: .loadingNextPage)
|
statusesState = .display(statuses: statuses, nextPageState: .loadingNextPage)
|
||||||
let newStatuses: [Status] = try await client.get(endpoint: timeline.endpoint(sinceId: lastId))
|
let newStatuses: [Status] = try await client.get(endpoint: timeline.endpoint(sinceId: nil, maxId: lastId))
|
||||||
statuses.append(contentsOf: newStatuses)
|
statuses.append(contentsOf: newStatuses)
|
||||||
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
Loading…
Reference in a new issue