Skip to content

Commit 201ab6e

Browse files
committed
hookup creator functions, album delete, misc fixes
1 parent dcd791d commit 201ab6e

File tree

6 files changed

+107
-18
lines changed

6 files changed

+107
-18
lines changed

Django Files/API/Albums.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,5 +138,23 @@ extension DFAPI {
138138
return nil
139139
}
140140
}
141+
142+
// Delete an album by ID
143+
func deleteAlbum(albumId: Int, selectedServer: DjangoFilesSession? = nil) async -> Bool {
144+
do {
145+
let path = "\(getAPIPath(.albums))\(albumId)"
146+
_ = try await makeAPIRequest(
147+
path: path,
148+
parameters: [:],
149+
method: .delete,
150+
expectedResponse: .noContent,
151+
selectedServer: selectedServer
152+
)
153+
return true
154+
} catch {
155+
print("Error deleting album: \(error)")
156+
return false
157+
}
158+
}
141159
}
142160

Django Files/API/DFAPI.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,16 @@ struct DFAPI {
9292
let session = URLSession(configuration: .ephemeral, delegate: taskDelegate, delegateQueue: .main)
9393
let (responseBody, response) = try await session.upload(for: request, from: body)
9494

95-
// Handle error responses
96-
if response.status != .ok {
95+
// Handle non-2xx responses
96+
if response.status.code < 200 || response.status.code >= 300 {
9797
await handleError(response.status, data: responseBody, selectedServer: selectedServer)
9898
throw URLError(.badServerResponse)
9999
}
100100

101101
return responseBody
102102
}
103103

104-
private func makeAPIRequest(path: String, parameters: [String:String], method: HTTPRequest.Method = .get, expectedResponse: HTTPResponse.Status = .ok, headerFields: [HTTPField.Name:String] = [:], taskDelegate: URLSessionTaskDelegate? = nil, selectedServer: DjangoFilesSession? = nil) async throws -> Data {
104+
internal func makeAPIRequest(path: String, parameters: [String:String], method: HTTPRequest.Method = .get, expectedResponse: HTTPResponse.Status = .ok, headerFields: [HTTPField.Name:String] = [:], taskDelegate: URLSessionTaskDelegate? = nil, selectedServer: DjangoFilesSession? = nil) async throws -> Data {
105105
var request = HTTPRequest(method: method, url: encodeParametersIntoURL(path: path, parameters: parameters))
106106
request.headerFields[.referer] = url.absoluteString
107107
request.headerFields[.authorization] = self.token
@@ -112,8 +112,8 @@ struct DFAPI {
112112
let session = URLSession(configuration: .ephemeral, delegate: taskDelegate ?? nil, delegateQueue: .main)
113113
let (responseBody, response) = try await session.upload(for: request, from: Data())
114114

115-
// Handle error responses
116-
if response.status != .ok {
115+
// Handle non-2xx responses
116+
if response.status.code < 200 || response.status.code >= 300 {
117117
await handleError(response.status, data: responseBody, selectedServer: selectedServer)
118118
throw URLError(.badServerResponse)
119119
}

Django Files/Views/AlbumList.swift

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ struct AlbumListView: View {
2020

2121
@State private var selectedAlbum: DFAlbum? = nil
2222
@State private var navigationPath = NavigationPath()
23+
@State private var isDeleting = false
24+
@State private var showDeleteConfirmation = false
25+
@State private var albumToDelete: DFAlbum? = nil
26+
@State private var showingAlbumCreator: Bool = false
2327

2428
var body: some View {
2529
ZStack {
@@ -66,6 +70,13 @@ struct AlbumListView: View {
6670
}) {
6771
Label("Copy Link", systemImage: "link")
6872
}
73+
74+
Button(role: .destructive, action: {
75+
albumToDelete = album
76+
showDeleteConfirmation = true
77+
}) {
78+
Label("Delete Album", systemImage: "trash")
79+
}
6980
}
7081
}
7182
.id(album.id)
@@ -86,7 +97,8 @@ struct AlbumListView: View {
8697
}
8798
}
8899
.navigationDestination(for: DFAlbum.self) { album in
89-
FileListView(server: server, albumID: album.id, navigationPath: $navigationPath)
100+
FileListView(server: server, albumID: album.id, navigationPath: $navigationPath, albumName: album.name)
101+
.navigationTitle("test")
90102
}
91103
.listStyle(.plain)
92104
.refreshable {
@@ -98,24 +110,42 @@ struct AlbumListView: View {
98110
.navigationTitle(server.wrappedValue != nil ? "Albums (\(URL(string: server.wrappedValue!.url)?.host ?? "unknown"))" : "Albums")
99111
.toolbar {
100112
ToolbarItem(placement: .navigationBarTrailing) {
101-
Menu {
102-
Button(action: {
103-
// Create album action
104-
}) {
105-
Label("Create Album", systemImage: "plus")
106-
}
107-
} label: {
108-
Image(systemName: "ellipsis.circle")
113+
Button(action: {
114+
showingAlbumCreator = true
115+
}) {
116+
Label("Create Album", systemImage: "plus")
109117
}
110118
}
111119
}
112120
}
121+
.sheet(isPresented: $showingAlbumCreator) {
122+
if let serverInstance = server.wrappedValue {
123+
CreateAlbumView(server: serverInstance)
124+
.onDisappear {
125+
showingAlbumCreator = false
126+
}
127+
}
128+
}
113129
.onChange(of: selectedAlbum) { oldValue, newValue in
114130
if let album = newValue {
115131
navigationPath.append(album)
116132
selectedAlbum = nil // Reset after navigation
117133
}
118134
}
135+
.alert("Delete Album", isPresented: $showDeleteConfirmation) {
136+
Button("Cancel", role: .cancel) {
137+
albumToDelete = nil
138+
}
139+
Button("Delete", role: .destructive) {
140+
if let album = albumToDelete {
141+
Task {
142+
await deleteAlbum(album)
143+
}
144+
}
145+
}
146+
} message: {
147+
Text("Are you sure you want to delete this album? This action cannot be undone.")
148+
}
119149
}
120150
}
121151
.onAppear {
@@ -181,6 +211,26 @@ struct AlbumListView: View {
181211
isLoading = false
182212
}
183213
}
214+
215+
@MainActor
216+
private func deleteAlbum(_ album: DFAlbum) async {
217+
guard let serverInstance = server.wrappedValue else { return }
218+
219+
isDeleting = true
220+
let api = DFAPI(url: URL(string: serverInstance.url)!, token: serverInstance.token)
221+
222+
if await api.deleteAlbum(albumId: album.id) {
223+
// Remove just the specific album from the list
224+
if let index = albums.firstIndex(where: { $0.id == album.id }) {
225+
albums.remove(at: index)
226+
}
227+
} else {
228+
ToastManager.shared.showToast(message: "Failed to delete album")
229+
}
230+
231+
isDeleting = false
232+
albumToDelete = nil
233+
}
184234
}
185235

186236
struct AlbumRowView: View {

Django Files/Views/FileList.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ struct FileRowView: View {
8080

8181

8282
HStack(spacing: 6) {
83-
Label(file.mime, systemImage: "")
83+
Text(file.mime)
8484
.font(.caption)
8585
.labelStyle(CustomLabel(spacing: 3))
8686
.lineLimit(1)
@@ -127,6 +127,7 @@ struct FileListView: View {
127127
let server: Binding<DjangoFilesSession?>
128128
let albumID: Int?
129129
let navigationPath: Binding<NavigationPath>
130+
let albumName: String?
130131

131132
@State private var files: [DFFile] = []
132133
@State private var currentPage = 1
@@ -158,6 +159,16 @@ struct FileListView: View {
158159

159160
@State private var showFileInfo: Bool = false
160161

162+
private func getTitle(server: Binding<DjangoFilesSession?>, albumName: String?) -> String {
163+
if server.wrappedValue != nil && albumName == nil {
164+
return "Files (\(String(describing: URL(string: server.wrappedValue?.url ?? "host")!.host ?? "unknown")))"
165+
} else if server.wrappedValue != nil && albumName != nil {
166+
return "\(String(describing: albumName!)) (\(String(describing: URL(string: server.wrappedValue?.url ?? "host")!.host ?? "unknown")))"
167+
} else {
168+
return "Files"
169+
}
170+
}
171+
161172
var body: some View {
162173
List {
163174
ForEach(files, id: \.id) { file in
@@ -236,7 +247,7 @@ struct FileListView: View {
236247
await refreshFiles()
237248
}
238249
}
239-
.navigationTitle(server.wrappedValue != nil ? "Files (\(URL(string: server.wrappedValue!.url)?.host ?? "unknown"))" : "Files")
250+
.navigationTitle(getTitle(server: server, albumName: albumName))
240251
.toolbar {
241252
ToolbarItem(placement: .navigationBarTrailing) {
242253
Menu {

Django Files/Views/ShortList.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ struct ShortListView: View {
1616
@State private var hasMoreResults = true
1717
@State private var error: String? = nil
1818

19+
@State private var showingShortCreator: Bool = false
20+
1921
private let shortsPerPage = 50
2022

2123
var body: some View {
@@ -48,12 +50,20 @@ struct ShortListView: View {
4850
.toolbar {
4951
ToolbarItem(placement: .navigationBarTrailing) {
5052
Button {
51-
// Create album action
53+
showingShortCreator = true
5254
} label: {
5355
Label("Create Short", systemImage: "plus")
5456
}
5557
}
5658
}
59+
.sheet(isPresented: $showingShortCreator) {
60+
if let serverInstance = server.wrappedValue {
61+
ShortCreatorView(server: serverInstance)
62+
.onDisappear {
63+
showingShortCreator = false
64+
}
65+
}
66+
}
5767

5868
}
5969
} else {

Django Files/Views/TabView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ struct TabViewWindow: View {
3030
TabView(selection: $selectedTab) {
3131
NavigationStack(path: $filesNavigationPath) {
3232
if let server = sessionManager.selectedSession {
33-
FileListView(server: .constant(server), albumID: nil, navigationPath: $filesNavigationPath)
33+
FileListView(server: .constant(server), albumID: nil, navigationPath: $filesNavigationPath, albumName: nil)
3434
.id(serverChangeRefreshTrigger)
3535
} else {
3636
Label("No server selected.", systemImage: "exclamationmark.triangle")

0 commit comments

Comments
 (0)