Documents navigation

This commit is contained in:
Arkadiusz Fal 2022-12-17 16:18:14 +01:00
parent cf0572a94b
commit 8e5bafba58
5 changed files with 43 additions and 80 deletions

View File

@ -3,24 +3,14 @@ import Foundation
final class DocumentsModel: ObservableObject { final class DocumentsModel: ObservableObject {
static var shared = DocumentsModel() static var shared = DocumentsModel()
@Published private(set) var directoryURL: URL!
@Published private(set) var refreshID = UUID() @Published private(set) var refreshID = UUID()
typealias AreInIncreasingOrder = (URL, URL) -> Bool typealias AreInIncreasingOrder = (URL, URL) -> Bool
init(directoryURL: URL! = nil) {
self.directoryURL = directoryURL
}
private var fileManager: FileManager { private var fileManager: FileManager {
.default .default
} }
var directoryLabel: String {
guard let directoryURL else { return "Documents" }
return displayLabelForDocument(directoryURL)
}
var sortPredicates: [AreInIncreasingOrder] { var sortPredicates: [AreInIncreasingOrder] {
[ [
{ self.isDirectory($0) && !self.isDirectory($1) }, { self.isDirectory($0) && !self.isDirectory($1) },
@ -28,8 +18,8 @@ final class DocumentsModel: ObservableObject {
] ]
} }
var sortedDirectoryContents: [URL] { func sortedDirectoryContents(_ directoryURL: URL) -> [URL] {
directoryContents.sorted { lhs, rhs in directoryContents(directoryURL).sorted { lhs, rhs in
for predicate in sortPredicates { for predicate in sortPredicates {
if !predicate(lhs, rhs), !predicate(rhs, lhs) { if !predicate(lhs, rhs), !predicate(rhs, lhs) {
continue continue
@ -42,9 +32,8 @@ final class DocumentsModel: ObservableObject {
} }
} }
var directoryContents: [URL] { func directoryContents(_ directoryURL: URL) -> [URL] {
guard let directoryURL else { return [] } contents(of: directoryURL)
return contents(of: directoryURL)
} }
var documentsDirectory: URL? { var documentsDirectory: URL? {
@ -157,7 +146,7 @@ final class DocumentsModel: ObservableObject {
)) ?? [] )) ?? []
} }
private func displayLabelForDocument(_ file: URL) -> String { func displayLabelForDocument(_ file: URL) -> String {
let components = file.absoluteString.components(separatedBy: "/Documents/") let components = file.absoluteString.components(separatedBy: "/Documents/")
if components.count == 2 { if components.count == 2 {
let component = components[1] let component = components[1]
@ -166,27 +155,6 @@ final class DocumentsModel: ObservableObject {
return "Document" return "Document"
} }
var canGoBack: Bool {
guard let directoryURL, let documentsDirectory else { return false }
return standardizedURL(directoryURL) != documentsDirectory
}
func goToURL(_ url: URL) {
directoryURL = url
}
func goBack() {
directoryURL = urlToGoBack
}
func goToTop() {
directoryURL = documentsDirectory
}
private var urlToGoBack: URL? {
directoryURL?.deletingLastPathComponent()
}
func standardizedURL(_ url: URL) -> URL? { func standardizedURL(_ url: URL) -> URL? {
let standardizedURL = NSString(string: url.absoluteString).standardizingPath let standardizedURL = NSString(string: url.absoluteString).standardizingPath
return URL(string: standardizedURL) return URL(string: standardizedURL)

View File

@ -1,18 +1,28 @@
import SwiftUI import SwiftUI
struct DocumentsView: View { struct DocumentsView: View {
var directoryURL: URL?
@ObservedObject private var model = DocumentsModel.shared @ObservedObject private var model = DocumentsModel.shared
var body: some View { var body: some View {
ScrollView(.vertical, showsIndicators: false) { ScrollView(.vertical, showsIndicators: false) {
if model.directoryContents.isEmpty { if let url, model.directoryContents(url).isEmpty {
NoDocumentsView() NoDocumentsView()
} else { } else if let url {
ForEach(model.sortedDirectoryContents, id: \.absoluteString) { url in ForEach(model.sortedDirectoryContents(url), id: \.absoluteString) { url in
let video = Video.local(model.standardizedURL(url) ?? url) let standardizedURL = model.standardizedURL(url) ?? url
PlayerQueueRow( let video = Video.local(standardizedURL)
item: PlayerQueueItem(video)
) Group {
if model.isDirectory(standardizedURL) {
NavigationLink(destination: DocumentsView(directoryURL: url)) {
VideoBanner(video: video)
}
} else {
PlayerQueueRow(item: PlayerQueueItem(video))
}
}
.contextMenu { .contextMenu {
VideoContextMenuView(video: video) VideoContextMenuView(video: video)
} }
@ -22,29 +32,7 @@ struct DocumentsView: View {
} }
Color.clear.padding(.bottom, 50) Color.clear.padding(.bottom, 50)
} }
.onAppear { .navigationTitle(directoryLabel)
if model.directoryURL.isNil {
model.goToTop()
}
}
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
if model.canGoBack {
Button {
withAnimation {
model.goBack()
}
} label: {
HStack(spacing: 6) {
Label("Go back", systemImage: "chevron.left")
}
}
.transaction { t in t.animation = .none }
.disabled(!model.canGoBack)
}
}
}
.navigationTitle(model.directoryLabel)
.padding(.horizontal) .padding(.horizontal)
.navigationBarTitleDisplayMode(RefreshControl.navigationBarTitleDisplayMode) .navigationBarTitleDisplayMode(RefreshControl.navigationBarTitleDisplayMode)
.backport .backport
@ -55,6 +43,15 @@ struct DocumentsView: View {
} }
} }
var url: URL? {
directoryURL ?? model.documentsDirectory
}
var directoryLabel: String {
guard let directoryURL else { return "Documents" }
return model.displayLabelForDocument(directoryURL)
}
func refresh() { func refresh() {
withAnimation { withAnimation {
model.refresh() model.refresh()

View File

@ -56,7 +56,7 @@ struct FavoriteItemView: View {
} }
func loadCacheAndResource(force: Bool = false) { func loadCacheAndResource(force: Bool = false) {
guard var resource else { return } guard let resource else { return }
var onSuccess: (Entity<Any>) -> Void = { _ in } var onSuccess: (Entity<Any>) -> Void = { _ in }
var contentItems = [ContentItem]() var contentItems = [ContentItem]()

View File

@ -92,7 +92,16 @@ struct HomeView: View {
if homeRecentDocumentsItems > 0 { if homeRecentDocumentsItems > 0 {
VStack { VStack {
HStack { HStack {
sectionLabel("Recent Documents") NavigationLink(destination: DocumentsView()) {
HStack {
Text("Documents")
.font(.title3.bold())
Image(systemName: "chevron.right")
.imageScale(.small)
}
.lineLimit(1)
}
.padding(.leading, 15)
Spacer() Spacer()

View File

@ -33,17 +33,6 @@ struct PlayerQueueRow: View {
return return
} }
#if os(iOS)
guard !video.localStreamIsDirectory else {
if let url = video.localStream?.localURL {
withAnimation {
DocumentsModel.shared.goToURL(url)
}
}
return
}
#endif
if video.localStreamIsFile, let url = video.localStream?.localURL { if video.localStreamIsFile, let url = video.localStream?.localURL {
URLBookmarkModel.shared.saveBookmark(url) URLBookmarkModel.shared.saveBookmark(url)
} }