Some improvements.
This commit is contained in:
parent
b9e130e15b
commit
9fbd39657e
|
@ -135,12 +135,13 @@ public extension MastodonClientAuthenticated {
|
|||
}
|
||||
|
||||
func favourites(maxId: EntityId? = nil,
|
||||
sinceId: EntityId? = nil,
|
||||
minId: EntityId? = nil,
|
||||
limit: Int? = nil) async throws -> [Status] {
|
||||
sinceId: EntityId? = nil,
|
||||
minId: EntityId? = nil,
|
||||
limit: Int? = nil,
|
||||
page: Page? = nil) async throws -> [Status] {
|
||||
let request = try Self.request(
|
||||
for: baseURL,
|
||||
target: Mastodon.Favourites.favourites(maxId, sinceId, minId, limit),
|
||||
target: Mastodon.Favourites.favourites(maxId, sinceId, minId, limit, page),
|
||||
withBearerToken: token
|
||||
)
|
||||
|
||||
|
@ -150,10 +151,11 @@ public extension MastodonClientAuthenticated {
|
|||
func bookmarks(maxId: EntityId? = nil,
|
||||
sinceId: EntityId? = nil,
|
||||
minId: EntityId? = nil,
|
||||
limit: Int? = nil) async throws -> [Status] {
|
||||
limit: Int? = nil,
|
||||
page: Page? = nil) async throws -> [Status] {
|
||||
let request = try Self.request(
|
||||
for: baseURL,
|
||||
target: Mastodon.Bookmarks.bookmarks(maxId, sinceId, minId, limit),
|
||||
target: Mastodon.Bookmarks.bookmarks(maxId, sinceId, minId, limit, page),
|
||||
withBearerToken: token
|
||||
)
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ public class MastodonClientAuthenticated: MastodonClientProtocol {
|
|||
|
||||
public func downloadJson<T>(_ type: T.Type, request: URLRequest) async throws -> T where T: Decodable {
|
||||
let (data, response) = try await urlSession.data(for: request)
|
||||
|
||||
|
||||
guard (response as? HTTPURLResponse)?.status?.responseType == .success else {
|
||||
throw NetworkError.notSuccessResponse(response)
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import Foundation
|
|||
|
||||
extension Mastodon {
|
||||
public enum Bookmarks {
|
||||
case bookmarks(MaxId?, SinceId?, MinId?, Limit?)
|
||||
case bookmarks(MaxId?, SinceId?, MinId?, Limit?, Page?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ extension Mastodon.Bookmarks: TargetType {
|
|||
/// The path to be appended to `baseURL` to form the full `URL`.
|
||||
public var path: String {
|
||||
switch self {
|
||||
case .bookmarks(_, _, _, _):
|
||||
case .bookmarks(_, _, _, _, _):
|
||||
return "\(apiPath)"
|
||||
}
|
||||
}
|
||||
|
@ -39,28 +39,37 @@ extension Mastodon.Bookmarks: TargetType {
|
|||
var sinceId: SinceId? = nil
|
||||
var minId: MinId? = nil
|
||||
var limit: Limit? = nil
|
||||
var page: Page? = nil
|
||||
|
||||
switch self {
|
||||
case .bookmarks(let _maxId, let _sinceId, let _minId, let _limit):
|
||||
case .bookmarks(let _maxId, let _sinceId, let _minId, let _limit, let _page):
|
||||
maxId = _maxId
|
||||
sinceId = _sinceId
|
||||
minId = _minId
|
||||
limit = _limit
|
||||
page = _page
|
||||
}
|
||||
|
||||
if let maxId {
|
||||
params.append(("max_id", maxId))
|
||||
}
|
||||
|
||||
if let sinceId {
|
||||
params.append(("since_id", sinceId))
|
||||
}
|
||||
|
||||
if let minId {
|
||||
params.append(("min_id", minId))
|
||||
}
|
||||
|
||||
if let limit {
|
||||
params.append(("limit", "\(limit)"))
|
||||
}
|
||||
|
||||
if let page {
|
||||
params.append(("page", "\(page)"))
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import Foundation
|
|||
|
||||
extension Mastodon {
|
||||
public enum Favourites {
|
||||
case favourites(MaxId?, SinceId?, MinId?, Limit?)
|
||||
case favourites(MaxId?, SinceId?, MinId?, Limit?, Page?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ extension Mastodon.Favourites: TargetType {
|
|||
/// The path to be appended to `baseURL` to form the full `URL`.
|
||||
public var path: String {
|
||||
switch self {
|
||||
case .favourites(_, _, _, _):
|
||||
case .favourites(_, _, _, _, _):
|
||||
return "\(apiPath)"
|
||||
}
|
||||
}
|
||||
|
@ -39,28 +39,37 @@ extension Mastodon.Favourites: TargetType {
|
|||
var sinceId: SinceId? = nil
|
||||
var minId: MinId? = nil
|
||||
var limit: Limit? = nil
|
||||
var page: Page? = nil
|
||||
|
||||
switch self {
|
||||
case .favourites(let _maxId, let _sinceId, let _minId, let _limit):
|
||||
case .favourites(let _maxId, let _sinceId, let _minId, let _limit, let _page):
|
||||
maxId = _maxId
|
||||
sinceId = _sinceId
|
||||
minId = _minId
|
||||
limit = _limit
|
||||
page = _page
|
||||
}
|
||||
|
||||
if let maxId {
|
||||
params.append(("max_id", maxId))
|
||||
}
|
||||
|
||||
if let sinceId {
|
||||
params.append(("since_id", sinceId))
|
||||
}
|
||||
|
||||
if let minId {
|
||||
params.append(("min_id", minId))
|
||||
}
|
||||
|
||||
if let limit {
|
||||
params.append(("limit", "\(limit)"))
|
||||
}
|
||||
|
||||
if let page {
|
||||
params.append(("page", "\(page)"))
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
||||
|
|
|
@ -54,3 +54,7 @@ In the status JSON we don't have information about bookmark status.
|
|||
- ** Endpoint about instance information returns different JSON structure**
|
||||
|
||||
API in Pixelfed (`/api/v1/instance`) returns JSON with diefferent structure then API specify.
|
||||
|
||||
- **There are some issues in bookmarks/favourites endpoints**
|
||||
|
||||
It seems like paging is not working in that endpoints (I've tried with page and max_id).
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
F8764187298ABB520057D362 /* ViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8764186298ABB520057D362 /* ViewState.swift */; };
|
||||
F8764189298ABEC80057D362 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8764188298ABEC80057D362 /* ErrorView.swift */; };
|
||||
F876418B298AC1B80057D362 /* NoDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F876418A298AC1B80057D362 /* NoDataView.swift */; };
|
||||
F876418D298AE5020057D362 /* PaginableStatusesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F876418C298AE5020057D362 /* PaginableStatusesView.swift */; };
|
||||
F87AEB922986C44E00434FB6 /* AuthorizationSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87AEB912986C44E00434FB6 /* AuthorizationSession.swift */; };
|
||||
F87AEB942986C51B00434FB6 /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87AEB932986C51B00434FB6 /* AppConstants.swift */; };
|
||||
F87AEB972986D16D00434FB6 /* AuthorisationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F87AEB962986D16D00434FB6 /* AuthorisationError.swift */; };
|
||||
|
@ -186,6 +187,7 @@
|
|||
F8764186298ABB520057D362 /* ViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewState.swift; sourceTree = "<group>"; };
|
||||
F8764188298ABEC80057D362 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = "<group>"; };
|
||||
F876418A298AC1B80057D362 /* NoDataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoDataView.swift; sourceTree = "<group>"; };
|
||||
F876418C298AE5020057D362 /* PaginableStatusesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginableStatusesView.swift; sourceTree = "<group>"; };
|
||||
F87AEB912986C44E00434FB6 /* AuthorizationSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorizationSession.swift; sourceTree = "<group>"; };
|
||||
F87AEB932986C51B00434FB6 /* AppConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = "<group>"; };
|
||||
F87AEB962986D16D00434FB6 /* AuthorisationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthorisationError.swift; sourceTree = "<group>"; };
|
||||
|
@ -313,6 +315,7 @@
|
|||
F88ABD9329687CA4004EF61E /* ComposeView.swift */,
|
||||
F89A46DB296EAACE0062125F /* SettingsView.swift */,
|
||||
F88E4D41297E69FD0057491A /* StatusesView.swift */,
|
||||
F876418C298AE5020057D362 /* PaginableStatusesView.swift */,
|
||||
F88E4D47297E90CD0057491A /* TrendStatusesView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
|
@ -714,6 +717,7 @@
|
|||
F866F6A529604194002E8F88 /* ApplicationSettingsHandler.swift in Sources */,
|
||||
F88ABD9229686F1C004EF61E /* MemoryCache.swift in Sources */,
|
||||
F857F9FD297D8ED3002C109C /* ActionMenu.swift in Sources */,
|
||||
F876418D298AE5020057D362 /* PaginableStatusesView.swift in Sources */,
|
||||
F85D49852964301800751DF7 /* StatusData+Attachments.swift in Sources */,
|
||||
F8764187298ABB520057D362 /* ViewState.swift in Sources */,
|
||||
F8210DE72966E1D1001D9973 /* Color+Assets.swift in Sources */,
|
||||
|
|
|
@ -21,6 +21,10 @@ extension View {
|
|||
imageHeight: metaImageHeight)
|
||||
case .statuses(let listType):
|
||||
StatusesView(listType: listType)
|
||||
case .bookmarks:
|
||||
PaginableStatusesView(listType: .bookmarks)
|
||||
case .favourites:
|
||||
PaginableStatusesView(listType: .favourites)
|
||||
case .userProfile(let accountId, let accountDisplayName, let accountUserName):
|
||||
UserProfileView(
|
||||
accountId: accountId,
|
||||
|
|
|
@ -127,25 +127,27 @@ public class AccountService {
|
|||
maxId: String? = nil,
|
||||
sinceId: String? = nil,
|
||||
minId: String? = nil,
|
||||
limit: Int = 40) async throws -> [Status] {
|
||||
limit: Int = 10,
|
||||
page: Int? = nil) async throws -> [Status] {
|
||||
guard let accessToken = account?.accessToken, let serverUrl = account?.serverUrl else {
|
||||
return []
|
||||
}
|
||||
|
||||
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
|
||||
return try await client.favourites(maxId: maxId, sinceId: sinceId, minId: minId, limit: limit)
|
||||
return try await client.favourites(limit: limit, page: page)
|
||||
}
|
||||
|
||||
public func bookmarks(for account: AccountModel?,
|
||||
maxId: String? = nil,
|
||||
sinceId: String? = nil,
|
||||
minId: String? = nil,
|
||||
limit: Int = 40) async throws -> [Status] {
|
||||
limit: Int = 10,
|
||||
page: Int? = nil) async throws -> [Status] {
|
||||
guard let accessToken = account?.accessToken, let serverUrl = account?.serverUrl else {
|
||||
return []
|
||||
}
|
||||
|
||||
let client = MastodonClient(baseURL: serverUrl).getAuthenticated(token: accessToken)
|
||||
return try await client.bookmarks(maxId: maxId, sinceId: sinceId, minId: minId, limit: limit)
|
||||
return try await client.bookmarks(limit: limit, page: page)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@ enum RouteurDestinations: Hashable {
|
|||
case tag(hashTag: String)
|
||||
case status(id: String, blurhash: String? = nil, highestImageUrl: URL? = nil, metaImageWidth: Int32? = nil, metaImageHeight: Int32? = nil)
|
||||
case statuses(listType: StatusesView.ListType)
|
||||
case bookmarks
|
||||
case favourites
|
||||
case userProfile(accountId: String, accountDisplayName: String?, accountUserName: String)
|
||||
case accounts(entityId: String, listType: AccountsView.ListType)
|
||||
case signIn
|
||||
|
|
|
@ -88,8 +88,10 @@ struct AccountsView: View {
|
|||
private func loadAccounts(page: Int) async {
|
||||
do {
|
||||
let accountsFromApi = try await self.loadFromApi()
|
||||
|
||||
if accountsFromApi.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
await self.downloadAvatars(accounts: accountsFromApi)
|
||||
|
|
|
@ -102,12 +102,13 @@ struct NotificationsView: View {
|
|||
maxId: self.maxId,
|
||||
limit: self.defaultPageSize)
|
||||
|
||||
self.maxId = linkable.link?.maxId
|
||||
self.notifications.append(contentsOf: linkable.data)
|
||||
|
||||
if linkable.data.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
self.maxId = linkable.link?.maxId
|
||||
self.notifications.append(contentsOf: linkable.data)
|
||||
} catch {
|
||||
ErrorService.shared.handle(error, message: "Error during download notifications from server.", showToastr: !Task.isCancelled)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// https://mczachurski.dev
|
||||
// Copyright © 2022 Marcin Czachurski and the repository contributors.
|
||||
// Licensed under the MIT License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import MastodonKit
|
||||
|
||||
struct PaginableStatusesView: View {
|
||||
public enum ListType: Hashable {
|
||||
case favourites
|
||||
case bookmarks
|
||||
}
|
||||
|
||||
@EnvironmentObject private var applicationState: ApplicationState
|
||||
@EnvironmentObject private var routerPath: RouterPath
|
||||
|
||||
@State public var listType: ListType
|
||||
|
||||
@State private var allItemsLoaded = false
|
||||
@State private var statusViewModels: [StatusModel] = []
|
||||
@State private var state: ViewState = .loading
|
||||
@State private var page = 1
|
||||
|
||||
private let defaultLimit = 10
|
||||
|
||||
var body: some View {
|
||||
self.mainBody()
|
||||
.navigationBarTitle(self.getTitle())
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func mainBody() -> some View {
|
||||
switch state {
|
||||
case .loading:
|
||||
LoadingIndicator()
|
||||
.task {
|
||||
await self.loadData()
|
||||
}
|
||||
case .loaded:
|
||||
if self.statusViewModels.isEmpty {
|
||||
NoDataView(imageSystemName: "photo.on.rectangle.angled", text: "Unfortunately, there are no photos here.")
|
||||
} else {
|
||||
ScrollView {
|
||||
LazyVStack(alignment: .center) {
|
||||
ForEach(self.statusViewModels, id: \.id) { item in
|
||||
NavigationLink(value: RouteurDestinations.status(
|
||||
id: item.id,
|
||||
blurhash: item.mediaAttachments.first?.blurhash,
|
||||
highestImageUrl: item.mediaAttachments.getHighestImage()?.url,
|
||||
metaImageWidth: item.getImageWidth(),
|
||||
metaImageHeight: item.getImageHeight())
|
||||
) {
|
||||
ImageRowAsync(statusViewModel: item)
|
||||
}
|
||||
.buttonStyle(EmptyButtonStyle())
|
||||
}
|
||||
|
||||
if allItemsLoaded == false {
|
||||
HStack {
|
||||
Spacer()
|
||||
LoadingIndicator()
|
||||
.task {
|
||||
do {
|
||||
try await self.loadMoreStatuses()
|
||||
} catch {
|
||||
ErrorService.shared.handle(error, message: "Loading more statuses failed.", showToastr: !Task.isCancelled)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case .error(let error):
|
||||
ErrorView(error: error) {
|
||||
self.state = .loading
|
||||
self.page = 1
|
||||
self.allItemsLoaded = false
|
||||
|
||||
await self.loadData()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadData() async {
|
||||
do {
|
||||
try await self.loadStatuses()
|
||||
self.state = .loaded
|
||||
} catch {
|
||||
ErrorService.shared.handle(error, message: "Loading statuses failed.", showToastr: !Task.isCancelled)
|
||||
self.state = .error(error)
|
||||
}
|
||||
}
|
||||
|
||||
private func loadStatuses() async throws {
|
||||
let statuses = try await self.loadFromApi()
|
||||
|
||||
if statuses.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: It seems that paging is not supported and we cannot download additiona data.
|
||||
self.allItemsLoaded = true
|
||||
|
||||
var inPlaceStatuses: [StatusModel] = []
|
||||
for item in statuses.getStatusesWithImagesOnly() {
|
||||
inPlaceStatuses.append(StatusModel(status: item))
|
||||
}
|
||||
|
||||
self.statusViewModels.append(contentsOf: inPlaceStatuses)
|
||||
}
|
||||
|
||||
private func loadMoreStatuses() async throws {
|
||||
self.page = self.page + 1
|
||||
|
||||
let previousStatuses = try await self.loadFromApi()
|
||||
|
||||
if previousStatuses.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
var inPlaceStatuses: [StatusModel] = []
|
||||
for item in previousStatuses.getStatusesWithImagesOnly() {
|
||||
inPlaceStatuses.append(StatusModel(status: item))
|
||||
}
|
||||
|
||||
self.statusViewModels.append(contentsOf: inPlaceStatuses)
|
||||
}
|
||||
|
||||
private func loadFromApi() async throws -> [Status] {
|
||||
switch self.listType {
|
||||
|
||||
case .favourites:
|
||||
return try await AccountService.shared.favourites(
|
||||
for: self.applicationState.account,
|
||||
limit: self.defaultLimit,
|
||||
page: self.page)
|
||||
case .bookmarks:
|
||||
return try await AccountService.shared.bookmarks(
|
||||
for: self.applicationState.account,
|
||||
limit: self.defaultLimit,
|
||||
page: self.page)
|
||||
}
|
||||
}
|
||||
|
||||
private func getTitle() -> String {
|
||||
switch self.listType {
|
||||
case .favourites:
|
||||
return "Favourites"
|
||||
case .bookmarks:
|
||||
return "Bookmarks"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ struct StatusesView: View {
|
|||
@State public var listType: ListType
|
||||
|
||||
@State private var allItemsLoaded = false
|
||||
@State private var firstLoadFinished = false
|
||||
@State private var tag: Tag?
|
||||
@State private var statusViewModels: [StatusModel] = []
|
||||
@State private var state: ViewState = .loading
|
||||
|
@ -51,34 +50,32 @@ struct StatusesView: View {
|
|||
NoDataView(imageSystemName: "photo.on.rectangle.angled", text: "Unfortunately, there are no photos here.")
|
||||
} else {
|
||||
ScrollView {
|
||||
if firstLoadFinished == true {
|
||||
LazyVStack(alignment: .center) {
|
||||
ForEach(self.statusViewModels, id: \.id) { item in
|
||||
NavigationLink(value: RouteurDestinations.status(
|
||||
id: item.id,
|
||||
blurhash: item.mediaAttachments.first?.blurhash,
|
||||
highestImageUrl: item.mediaAttachments.getHighestImage()?.url,
|
||||
metaImageWidth: item.getImageWidth(),
|
||||
metaImageHeight: item.getImageHeight())
|
||||
) {
|
||||
ImageRowAsync(statusViewModel: item)
|
||||
}
|
||||
.buttonStyle(EmptyButtonStyle())
|
||||
LazyVStack(alignment: .center) {
|
||||
ForEach(self.statusViewModels, id: \.id) { item in
|
||||
NavigationLink(value: RouteurDestinations.status(
|
||||
id: item.id,
|
||||
blurhash: item.mediaAttachments.first?.blurhash,
|
||||
highestImageUrl: item.mediaAttachments.getHighestImage()?.url,
|
||||
metaImageWidth: item.getImageWidth(),
|
||||
metaImageHeight: item.getImageHeight())
|
||||
) {
|
||||
ImageRowAsync(statusViewModel: item)
|
||||
}
|
||||
|
||||
if allItemsLoaded == false && firstLoadFinished == true {
|
||||
HStack {
|
||||
Spacer()
|
||||
LoadingIndicator()
|
||||
.task {
|
||||
do {
|
||||
try await self.loadMoreStatuses()
|
||||
} catch {
|
||||
ErrorService.shared.handle(error, message: "Loading more statuses failed.", showToastr: !Task.isCancelled)
|
||||
}
|
||||
.buttonStyle(EmptyButtonStyle())
|
||||
}
|
||||
|
||||
if allItemsLoaded == false {
|
||||
HStack {
|
||||
Spacer()
|
||||
LoadingIndicator()
|
||||
.task {
|
||||
do {
|
||||
try await self.loadMoreStatuses()
|
||||
} catch {
|
||||
ErrorService.shared.handle(error, message: "Loading more statuses failed.", showToastr: !Task.isCancelled)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,18 +113,18 @@ struct StatusesView: View {
|
|||
}
|
||||
|
||||
private func loadStatuses() async throws {
|
||||
guard firstLoadFinished == false else {
|
||||
let statuses = try await self.loadFromApi()
|
||||
|
||||
if statuses.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
let statuses = try await self.loadFromApi()
|
||||
|
||||
var inPlaceStatuses: [StatusModel] = []
|
||||
|
||||
for item in statuses.getStatusesWithImagesOnly() {
|
||||
inPlaceStatuses.append(StatusModel(status: item))
|
||||
}
|
||||
|
||||
self.firstLoadFinished = true
|
||||
self.statusViewModels.append(contentsOf: inPlaceStatuses)
|
||||
}
|
||||
|
||||
|
@ -137,6 +134,7 @@ struct StatusesView: View {
|
|||
|
||||
if previousStatuses.isEmpty {
|
||||
self.allItemsLoaded = true
|
||||
return
|
||||
}
|
||||
|
||||
var inPlaceStatuses: [StatusModel] = []
|
||||
|
|
|
@ -136,11 +136,11 @@ struct UserProfileView: View {
|
|||
Divider()
|
||||
}
|
||||
|
||||
NavigationLink(value: RouteurDestinations.statuses(listType: .favourites)) {
|
||||
NavigationLink(value: RouteurDestinations.favourites) {
|
||||
Label("Favourites", systemImage: "hand.thumbsup")
|
||||
}
|
||||
|
||||
NavigationLink(value: RouteurDestinations.statuses(listType: .bookmarks)) {
|
||||
NavigationLink(value: RouteurDestinations.bookmarks) {
|
||||
Label("Bookmarks", systemImage: "bookmark")
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue