Skip to content

Commit

Permalink
fix: Show icons for downloads (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbmorley authored Dec 12, 2024
1 parent 943b227 commit 0034834
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 45 deletions.
4 changes: 4 additions & 0 deletions Reconnect.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
D89071912C4B025D00C11DE8 /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = D89071902C4B025D00C11DE8 /* ArgumentParser */; };
D89071932C4B02D900C11DE8 /* ReconnectCore in Frameworks */ = {isa = PBXBuildFile; productRef = D89071922C4B02D900C11DE8 /* ReconnectCore */; };
D89B5E8E2C2AA8680014A5B6 /* Sidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D89B5E8D2C2AA8680014A5B6 /* Sidebar.swift */; };
D8AB7ED32D0AA1140076E19F /* FileReference.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8AB7ED22D0AA1130076E19F /* FileReference.swift */; };
D8AE29A82CA25A9800116439 /* PsionSoftwareIndex in Frameworks */ = {isa = PBXBuildFile; productRef = D8AE29A72CA25A9800116439 /* PsionSoftwareIndex */; };
D8CBAC652C4A02580035FC3D /* ReconnectCore in Frameworks */ = {isa = PBXBuildFile; productRef = D8CBAC642C4A02580035FC3D /* ReconnectCore */; };
D8D3E79F2C2540D9003E696D /* Interact in Frameworks */ = {isa = PBXBuildFile; productRef = D8D3E79E2C2540D9003E696D /* Interact */; };
Expand Down Expand Up @@ -137,6 +138,7 @@
D89071882C4B01FC00C11DE8 /* screenshot-sis */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "screenshot-sis"; sourceTree = BUILT_PRODUCTS_DIR; };
D890718A2C4B01FC00C11DE8 /* Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
D89B5E8D2C2AA8680014A5B6 /* Sidebar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sidebar.swift; sourceTree = "<group>"; };
D8AB7ED22D0AA1130076E19F /* FileReference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileReference.swift; sourceTree = "<group>"; };
D8AD8B532C2379A10063A613 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
D8D3E7A02C25410E003E696D /* MainMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainMenu.swift; sourceTree = "<group>"; };
D8E31EB42C26E10900350082 /* Licensable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Licensable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -224,6 +226,7 @@
D8184C462C253C59008FA79B /* ApplicationModel.swift */,
D886DA752C29343900E84BDA /* BrowserModel.swift */,
D83B4DE02C2F99C3003C3DC1 /* CheckForUpdatesViewModel.swift */,
D8AB7ED22D0AA1130076E19F /* FileReference.swift */,
D8631DB02C374B0A00344DC3 /* Transfer.swift */,
D8631DB22C374B4400344DC3 /* TransfersModel.swift */,
);
Expand Down Expand Up @@ -607,6 +610,7 @@
D83658BB2C29A09300B45693 /* HistoryItemView.swift in Sources */,
D8E31EB52C26E10900350082 /* Licensable.swift in Sources */,
D886DA742C28CDAD00E84BDA /* BrowserView.swift in Sources */,
D8AB7ED32D0AA1140076E19F /* FileReference.swift in Sources */,
D88FA1502C2CE29900805DBD /* ContentView.swift in Sources */,
D83B4DE12C2F99C3003C3DC1 /* CheckForUpdatesViewModel.swift in Sources */,
D8FFE85F2C49F2FB001F7D8A /* TransfersWindow.swift in Sources */,
Expand Down
11 changes: 6 additions & 5 deletions Reconnect/Model/BrowserModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,12 @@ class BrowserModel {
func download(_ selection: Set<FileServer.DirectoryEntry.ID>? = nil, convertFiles: Bool) {
NSWorkspace.shared.open(.transfers)
let selection = selection ?? fileSelection
for path in selection {
if path.isWindowsDirectory {
downloadDirectory(path: path, convertFiles: convertFiles)
let files = files.filter { selection.contains($0.id) }
for file in files {
if file.path.isWindowsDirectory {
downloadDirectory(path: file.path, convertFiles: convertFiles)
} else {
transfersModel.download(from: path, convertFiles: convertFiles)
transfersModel.download(from: file, convertFiles: convertFiles)
}
}
}
Expand All @@ -242,7 +243,7 @@ class BrowserModel {
if file.isDirectory {
try fileManager.createDirectory(at: destinationURL, withIntermediateDirectories: true)
} else {
self.transfersModel.download(from: file.path, to: destinationURL, convertFiles: convertFiles)
self.transfersModel.download(from: file, to: destinationURL, convertFiles: convertFiles)
}
}
}
Expand Down
41 changes: 41 additions & 0 deletions Reconnect/Model/FileReference.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Reconnect -- Psion connectivity for macOS
//
// Copyright (C) 2024 Jason Morley
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import Foundation

import ReconnectCore

enum FileReference {

case local(URL)
case remote(FileServer.DirectoryEntry)

}

extension FileReference {

var name: String {
switch self {
case .local(let url):
return url.lastPathComponent
case .remote(let directoryEntry):
return directoryEntry.name
}
}

}
8 changes: 4 additions & 4 deletions Reconnect/Model/Transfer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class Transfer: Identifiable {
}

let id = UUID()
let title: String
let item: FileReference

var status: Status

Expand All @@ -80,9 +80,9 @@ class Transfer: Identifiable {
}
}

init(title: String, action: @escaping (Transfer) async throws -> Void) {
self.title = title
self.status = .waiting
init(item: FileReference, status: Status = .waiting, action: @escaping ((Transfer) async throws -> Void) = { _ in }) {
self.item = item
self.status = status
let task = Task {
do {
try await action(self)
Expand Down
44 changes: 31 additions & 13 deletions Reconnect/Model/TransfersModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,20 @@ class TransfersModel {
init() {
}

func add(_ title: String, action: @escaping (Transfer) async throws -> Void) {
transfers.append(Transfer(title: title, action: action))
}

func download(from sourcePath: String, to destinationURL: URL? = nil, convertFiles: Bool) {
func download(from source: FileServer.DirectoryEntry, to destinationURL: URL? = nil, convertFiles: Bool) {
let fileManager = FileManager.default
let downloadsURL = fileManager.urls(for: .downloadsDirectory, in: .userDomainMask)[0]
let filename = sourcePath.lastWindowsPathComponent
let filename = source.path.lastWindowsPathComponent
let downloadURL = destinationURL ?? downloadsURL.appendingPathComponent(filename)
print("Downloading file at path '\(sourcePath)' to destination path '\(downloadURL.path)'...")
print("Downloading file at path '\(source.path)' to destination path '\(downloadURL.path)'...")

add(filename) { transfer in
transfers.append(Transfer(item: .remote(source)) { transfer in

// Get the file information.
let directoryEntry = try await self.fileServer.getExtendedAttributes(path: sourcePath)
let directoryEntry = try await self.fileServer.getExtendedAttributes(path: source.path)

// Perform the file copy.
try await self.fileServer.copyFile(fromRemotePath: sourcePath, toLocalPath: downloadURL.path) { progress, size in
try await self.fileServer.copyFile(fromRemotePath: source.path, toLocalPath: downloadURL.path) { progress, size in
transfer.setStatus(.active(Float(progress) / Float(size)))
return transfer.isCancelled ? .cancel : .continue
}
Expand All @@ -73,22 +69,44 @@ class TransfersModel {

// Mark the transfer as complete.
transfer.setStatus(.complete(urls.first))
}
})
}

func upload(from sourceURL: URL, to destinationPath: String) {
print("Uploading file at path '\(sourceURL.path)' to destination path '\(destinationPath)'...")
add(sourceURL.lastPathComponent) { transfer in
transfers.append(Transfer(item: .local(sourceURL)) { transfer in
try await self.fileServer.copyFile(fromLocalPath: sourceURL.path, toRemotePath: destinationPath) { progress, size in
transfer.setStatus(.active(Float(progress) / Float(size)))
return transfer.isCancelled ? .cancel : .continue
}
transfer.setStatus(.complete(nil))
}
})
}

func clear() {
transfers.removeAll { !$0.isActive }
}

}

extension TransfersModel {

func addDemoData() {
let remoteFile = FileServer.DirectoryEntry(path: "D:\\Screenshots\\Thoughts Splash Screen",
name: "Thoughts Splash Screen",
size: 203,
attributes: .normal,
modificationDate: .now,
uid1: .directFileStore,
uid2: .appDllDoc,
uid3: .sketch)
let error = ReconnectError.rfsvError(.init(rawValue: -37))
transfers.append(Transfer(item: .remote(remoteFile),
status: .waiting))
transfers.append(Transfer(item: .remote(remoteFile),
status: .failed(error)))
transfers.append(Transfer(item: .local(URL(fileURLWithPath: "/Users/jbmorley/Thoughts Screenshot.png")),
status: .cancelled))
}

}
72 changes: 49 additions & 23 deletions Reconnect/Views/TransferRow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,68 @@ import Interact
struct TransferRow: View {

let transfer: Transfer

var image: some View {
switch transfer.item {
case .local:
Image(.fileUnknown16)
.interpolation(.none)
.resizable()
.frame(width: 32, height: 32)
case .remote(let file):
Image(file.fileType.image)
.interpolation(.none)
.resizable()
.frame(width: 32, height: 32)
}
}

var statusText: String {
switch transfer.status {
case .waiting:
return "Waiting to start…"
case .active(let progress):
return progress.formatted()
case .complete:
return "Complete"
case .cancelled:
return "Cancelled"
case .failed(let error):
return error.localizedDescription
}

}

var body: some View {
HStack {
HStack(spacing: 16.0) {

self.image

VStack(alignment: .leading, spacing: 0) {

Text(transfer.title)


Text(transfer.item.name)
.lineLimit(1)
.truncationMode(.middle)
.horizontalSpace(.trailing)

switch transfer.status {
case .waiting:
ProgressView(value: 0)
.controlSize(.small)
case .active(let progress):
ProgressView(value: progress)
.controlSize(.small)
Text(progress.formatted())
.foregroundStyle(.secondary)
.font(.callout)
case .complete:
Text("Complete")
.foregroundStyle(.secondary)
.font(.callout)
case .cancelled:
Text("Cancelled")
case .failed(let error):
Text(error.localizedDescription)
.foregroundStyle(.secondary)
.font(.callout)
case .complete, .cancelled, .failed:
EmptyView()
}


Text(statusText)
.lineLimit(1)
.foregroundStyle(.secondary)
.font(.callout)

}

Spacer()


switch transfer.status {
case .waiting, .active:
Button {
Expand Down Expand Up @@ -89,5 +117,3 @@ struct TransferRow: View {
}

}


8 changes: 8 additions & 0 deletions Reconnect/Views/TransfersView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,15 @@ struct TransfersView: View {
Divider()
HStack {
Toggle("Convert Files", isOn: $applicationModel.convertFiles)

Spacer()

#if DEBUG
Button("Add Demo Data") {
transfersModel.addDemoData()
}
#endif

Button("Clear") {
transfersModel.clear()
}
Expand Down
18 changes: 18 additions & 0 deletions ReconnectCore/Sources/ReconnectCore/PLP/FileServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ public class FileServer {
public let uid1: UInt32
public let uid2: UInt32
public let uid3: UInt32

public init(path: String,
name: String,
size: UInt32,
attributes: FileAttributes,
modificationDate: Date,
uid1: UInt32,
uid2: UInt32,
uid3: UInt32) {
self.path = path
self.name = name
self.size = size
self.attributes = attributes
self.modificationDate = modificationDate
self.uid1 = uid1
self.uid2 = uid2
self.uid3 = uid3
}

init(directoryPath: String, entry: PlpDirent) {
var entry = entry
Expand Down

0 comments on commit 0034834

Please sign in to comment.