Skip to content

Commit 272bac6

Browse files
committed
wip
1 parent dac2136 commit 272bac6

File tree

4 files changed

+97
-101
lines changed

4 files changed

+97
-101
lines changed

Examples/SupaDrive/AppView.swift

+80-96
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ import IdentifiedCollections
1313
@MainActor
1414
@Observable
1515
final class AppModel {
16-
var panels: IdentifiedArrayOf<PanelModel> {
16+
let root: PanelModel
17+
18+
var panels: IdentifiedArrayOf<PanelModel> = [] {
1719
didSet {
1820
bindPanelModels()
1921
}
2022
}
2123

22-
init(panels: IdentifiedArrayOf<PanelModel>) {
23-
self.panels = panels
24+
init(root: PanelModel) {
25+
self.root = root
2426
bindPanelModels()
2527
}
2628

@@ -33,22 +35,15 @@ final class AppModel {
3335
}
3436

3537
var selectedFile: FileObject? {
36-
panels.last?.selectedItem
38+
nil// panels.last?.selectedItem
3739
}
3840

3941
private func bindPanelModels() {
40-
for panel in panels {
42+
for panel in [root] + panels {
4143
panel.onSelectItem = { [weak self, weak panel] item in
4244
guard let self, let panel else { return }
4345

44-
// self.panels.append(PanelModel(path: self.path.appending))
45-
//
46-
// if let name = item.name, item.id == nil {
47-
// self.panels.replaceSubrange(
48-
// (index + 1)...,
49-
// with: [PanelModel(path: self.path.appending("/\(name)"))]
50-
// )
51-
// }
46+
self.panels.append(PanelModel(path: panel.path.appending("/\(item.name!)")))
5247
}
5348
}
5449
}
@@ -58,35 +53,11 @@ struct AppView: View {
5853
@Bindable var model: AppModel
5954

6055
var body: some View {
61-
VStack(alignment: .leading, spacing: 0) {
62-
breadcrump
63-
64-
ScrollView(.horizontal) {
65-
HStack {
66-
ForEach(model.panels) { panel in
67-
PanelView(
68-
model: panel
69-
// model: PanelModel(path: path[0 ... pathIndex].joined(separator: "/"))
70-
// path: path[0 ... pathIndex].joined(separator: "/"),
71-
// selectedItem: Binding(
72-
// get: {
73-
// selectedItemPerPath[path[pathIndex]]
74-
// },
75-
// set: { newValue in
76-
// selectedItemPerPath[path[pathIndex]] = newValue
77-
//
78-
// if let newValue, let name = newValue.name, newValue.id == nil {
79-
// path.replaceSubrange((pathIndex + 1)..., with: [name])
80-
// } else {
81-
// path.replaceSubrange((pathIndex + 1)..., with: [])
82-
// }
83-
// }
84-
// )
85-
)
86-
.frame(width: 200)
87-
}
56+
NavigationStack(path: $model.panels) {
57+
PanelView(model: model.root)
58+
.navigationDestination(for: PanelModel.self) { model in
59+
PanelView(model: model)
8860
}
89-
}
9061
}
9162
.overlay(alignment: .trailing) {
9263
if let selectedFile = model.selectedFile {
@@ -110,24 +81,8 @@ struct AppView: View {
11081
.transition(.move(edge: .trailing))
11182
}
11283
}
113-
.animation(.default, value: model.path)
114-
.animation(.default, value: model.selectedFile)
115-
}
116-
117-
var breadcrump: some View {
118-
HStack {
119-
ForEach(Array(zip(model.pathComponents.indices, model.pathComponents)), id: \.0) { idx, path in
120-
Button(path) {
121-
// self.path.replaceSubrange((idx + 1)..., with: [])
122-
}
123-
.buttonStyle(.plain)
124-
125-
// if idx != self.path.indices.last {
126-
// Text(">")
127-
// }
128-
}
129-
}
130-
.padding()
84+
// .animation(.default, value: model.path)
85+
// .animation(.default, value: model.selectedFile)
13186
}
13287
}
13388

@@ -138,9 +93,17 @@ struct DragValue: Codable {
13893

13994
@MainActor
14095
@Observable
141-
final class PanelModel: Identifiable {
96+
final class PanelModel: Identifiable, Hashable {
97+
nonisolated func hash(into hasher: inout Hasher) {
98+
hasher.combine(ObjectIdentifier(self))
99+
}
100+
101+
nonisolated static func == (lhs: PanelModel, rhs: PanelModel) -> Bool {
102+
lhs === rhs
103+
}
104+
142105
let path: String
143-
var selectedItem: FileObject?
106+
var selectedItem: FileObject.ID?
144107

145108
var items: [FileObject] = []
146109

@@ -160,15 +123,21 @@ final class PanelModel: Identifiable {
160123
}
161124
}
162125

163-
func didSelectItem(_ item: FileObject) {
164-
self.selectedItem = item
126+
func onPrimaryAction(_ itemID: FileObject.ID) {
127+
guard let item = items.first(where: { $0.id == itemID }) else { return }
165128
onSelectItem(item)
166129
}
167130

131+
// func didSelectItem(_ item: FileObject) {
132+
// self.selectedItem = item
133+
// onSelectItem(item)
134+
// }
135+
168136
func newFolderButtonTapped() async {
169137
do {
170138
try await supabase.storage.from("main")
171139
.upload(path: "\(path)/Untiltled/.dummy", file: Data())
140+
await load()
172141
} catch {
173142

174143
}
@@ -181,6 +150,7 @@ final class PanelModel: Identifiable {
181150
let file = try Data(contentsOf: url)
182151
try await supabase.storage.from("main")
183152
.upload(path: "\(self.path)/\(path)", file: file)
153+
await load()
184154
} catch {}
185155
}
186156
}
@@ -191,33 +161,58 @@ struct PanelView: View {
191161
@State private var isDraggingOver = false
192162

193163
var body: some View {
194-
List {
195-
ForEach(model.items) { item in
196-
Text(item.name ?? "")
197-
.bold(model.selectedItem == item)
198-
.onTapGesture {
199-
model.didSelectItem(item)
200-
}
201-
.onDrag {
202-
let data = try! JSONEncoder().encode(DragValue(path: model.path, object: item))
203-
let string = String(decoding: data, as: UTF8.self)
204-
return NSItemProvider(object: string as NSString)
205-
}
164+
Table(model.items, selection: $model.selectedItem) {
165+
TableColumn("Name") { item in
166+
Text(item.name ?? "No name")
206167
}
207-
.onInsert(of: ["public.text"]) { index, items in
208-
for item in items {
209-
Task {
210-
guard let data = try await item.loadItem(forTypeIdentifier: "public.text") as? Data,
211-
let value = try? JSONDecoder().decode(DragValue.self, from: data) else {
212-
return
213-
}
214168

215-
self.model.items.insert(value.object, at: index)
216-
}
169+
TableColumn("Date modified") { item in
170+
if let lastModifiedStringValue = item.metadata?["lastModified"]?.stringValue,
171+
let lastModified = try? Date(lastModifiedStringValue, strategy: .iso8601.day().month().year().dateTimeSeparator(.standard).time(includingFractionalSeconds: true))
172+
{
173+
Text(lastModified.formatted(date: .abbreviated, time: .shortened))
174+
} else {
175+
Text("-")
176+
}
177+
}
178+
179+
TableColumn("Size") { item in
180+
if let sizeRawValue = item.metadata?["size"]?.intValue {
181+
Text(sizeRawValue.formatted(.byteCount(style: .file)))
182+
} else {
183+
Text("-")
217184
}
218-
print(index, items)
219185
}
220186
}
187+
.contextMenu(
188+
forSelectionType: FileObject.ID.self,
189+
menu: { items in
190+
Button("New folder") {
191+
Task {
192+
await model.newFolderButtonTapped()
193+
}
194+
}
195+
},
196+
primaryAction: { items in
197+
guard let item = items.first else { return }
198+
199+
model.onPrimaryAction(item)
200+
}
201+
)
202+
// .onInsert(of: ["public.text"]) { index, items in
203+
// for item in items {
204+
// Task {
205+
// guard let data = try await item.loadItem(forTypeIdentifier: "public.text") as? Data,
206+
// let value = try? JSONDecoder().decode(DragValue.self, from: data) else {
207+
// return
208+
// }
209+
//
210+
// self.model.items.insert(value.object, at: index)
211+
// }
212+
// }
213+
// print(index, items)
214+
// }
215+
.navigationTitle(model.path)
221216
.task {
222217
await model.load()
223218
}
@@ -240,16 +235,5 @@ struct PanelView: View {
240235
Color.gray.opacity(0.2)
241236
}
242237
}
243-
.contextMenu {
244-
Button("New folder") {
245-
Task {
246-
await model.newFolderButtonTapped()
247-
}
248-
}
249-
}
250238
}
251239
}
252-
253-
#Preview {
254-
AppView(model: AppModel(panels: []))
255-
}

Examples/SupaDrive/SupaDriveApp.swift

+15-5
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,26 @@
77

88
import Supabase
99
import SwiftUI
10+
import OSLog
1011

1112
let supabase = SupabaseClient(
1213
supabaseURL: URL(string: "http://127.0.0.1:54321")!,
1314
supabaseKey: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0",
14-
options: SupabaseClientOptions(global: .init(logger: AppLogger()))
15+
options: SupabaseClientOptions(global: .init(logger: Logger.supabase))
1516
)
1617

17-
struct AppLogger: SupabaseLogger {
18-
func log(message: SupabaseLogMessage) {
19-
print(message.description)
18+
extension Logger: @retroactive SupabaseLogger {
19+
static let supabase = Logger(subsystem: "supadrive", category: "supabase")
20+
21+
public func log(message: SupabaseLogMessage) {
22+
let logType: OSLogType = switch message.level {
23+
case .debug: .debug
24+
case .error: .error
25+
case .verbose: .info
26+
case .warning: .fault
27+
}
28+
29+
self.log(level: logType, "\(message)")
2030
}
2131
}
2232

@@ -26,7 +36,7 @@ struct SupaDriveApp: App {
2636
WindowGroup {
2737
AuthView { session in
2838
AppView(
29-
model: AppModel(panels: [PanelModel(path: session.user.id.uuidString.lowercased())])
39+
model: AppModel(root: PanelModel(path: session.user.id.uuidString.lowercased()))
3040
)
3141
}
3242
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
main
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
v1.183.5

0 commit comments

Comments
 (0)