13 Commits
141 changed files with 851 additions and 614 deletions

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 527 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 488 KiB

After

Width:  |  Height:  |  Size: 488 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 492 KiB

After

Width:  |  Height:  |  Size: 492 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 527 KiB

After

Width:  |  Height:  |  Size: 527 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File renamed without changes.
File renamed without changes.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 158 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 488 KiB

After

Width:  |  Height:  |  Size: 488 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 492 KiB

After

Width:  |  Height:  |  Size: 492 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 527 KiB

After

Width:  |  Height:  |  Size: 527 KiB

File renamed without changes.
File renamed without changes.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 752 KiB

After

Width:  |  Height:  |  Size: 752 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 527 KiB

After

Width:  |  Height:  |  Size: 527 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 105 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 752 KiB

After

Width:  |  Height:  |  Size: 752 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 527 KiB

After

Width:  |  Height:  |  Size: 527 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 3.2 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

-147
View File
@@ -1,147 +0,0 @@
//
// Logger.swift
// QuickDrop
//
// Created by Leon Böttger on 26.02.25.
//
import Foundation
import os
fileprivate let loggerQueue = DispatchQueue(label: "loggerQueue")
/// Manages logging functionality
final class LogManager {
/// The URL of the log file
let logFileURL: URL?
/// The private initializer
private init() {
/// Get documents directory
let directory = getDocumentsDirectory()
/// Create file name from date
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-yyyy"
let dateString = formatter.string(from: Date())
let fileName = "\(dateString).log"
/// Create file URL from file name
self.logFileURL = directory.appendingPathComponent(fileName)
}
/// The shared instance.
public static let sharedInstance = LogManager()
@Published var loggingEnabled = true
/// Writes a specified string to the log file.
func writeToFile(string: String) {
/// Make sure the URL is not nil
guard let logFileURL = logFileURL else {
return
}
/// Get current timestamp
let formatter = DateFormatter()
formatter.dateFormat = "HH:mm:ss"
let timestamp = formatter.string(from: Date())
/// Create data from string and timestamp
guard let data = (timestamp + " - " + string + "\n").data(using: .utf8) else { return }
/// a log file exists already
if FileManager.default.fileExists(atPath: logFileURL.path) {
/// we try to get a handle to write to the log file
if let file = try? FileHandle(forWritingTo: logFileURL) {
/// go to end of file
file.seekToEndOfFile()
/// write string to end
file.write(data)
///close file
file.closeFile()
}
} else {
/// Clean up older logs
deleteLogs()
/// create new log file
try? data.write(to: logFileURL, options: .atomicWrite)
}
}
func getLogString() -> String {
if let logFileURL = logFileURL {
let fileURL = URL(fileURLWithPath: logFileURL.path)
do {
let content = try String(contentsOf: fileURL, encoding: .utf8)
return String(content)
} catch {
log("[LUI] Error reading file: \(error.localizedDescription)")
}
}
return ""
}
/// Deletes all log files.
func deleteLogs() {
log("[LUI] Deleting all logs...")
let fileManager = FileManager.default
let documentsDirectory = getDocumentsDirectory()
guard let allFiles = try? fileManager.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil) else {
return
}
let logFiles = allFiles.filter { $0.pathExtension.elementsEqual("log") }
for file in logFiles {
do {
log("[LUI] Removing \(file.description)")
try fileManager.removeItem(at: file)
} catch {
print(error.localizedDescription)
}
}
}
}
/// Logs a specified string.
public func log(_ text: String) {
let logger = LogManager.sharedInstance
if logger.loggingEnabled {
loggerQueue.async {
print(text)
// Weird bug?
#if !os(tvOS)
logger.writeToFile(string: text)
#endif
}
}
}
/// Returns the URL of the documents directory.
func getDocumentsDirectory() -> URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
}
+68 -8
View File
@@ -11,7 +11,7 @@ import CryptoKit
import Foundation
import Network
import System
import ImageIO
import BigInt
import SwiftECC
@@ -64,19 +64,23 @@ class InboundNearbyConnection: NearbyConnection {
try processConnectionResponseFrame(frame)
default:
var smsg: Securemessage_SecureMessage? = nil
do {
let smsg = try Securemessage_SecureMessage(serializedBytes: frameData)
try decryptAndProcessReceivedSecureMessage(smsg)
smsg = try Securemessage_SecureMessage(serializedBytes: frameData)
} catch {
log("Error deserializing secure message (probably due to packet filter)")
lastError = NearbyError.packetFilterError
protocolError()
}
if let smsg = smsg {
try decryptAndProcessReceivedSecureMessage(smsg)
}
}
} catch {
lastError = error
log("Deserialization error: \(error) in state \(currentState).")
log("Error receiving frame: \(error) in state \(currentState).")
protocolError()
}
}
@@ -117,9 +121,15 @@ class InboundNearbyConnection: NearbyConnection {
guard currentOffset + Int64(frame.payloadChunk.body.count) <= fileInfo.meta.size else { throw NearbyError.protocolError("Transferred file size exceeds previously specified value") }
if frame.payloadChunk.body.count > 0 {
fileInfo.fileHandle?.write(frame.payloadChunk.body)
transferredFiles[id]!.bytesTransferred += Int64(frame.payloadChunk.body.count)
fileInfo.progress?.completedUnitCount = transferredFiles[id]!.bytesTransferred
do {
try fileInfo.fileHandle?.write(contentsOf: frame.payloadChunk.body)
transferredFiles[id]!.bytesTransferred += Int64(frame.payloadChunk.body.count)
fileInfo.progress?.completedUnitCount = transferredFiles[id]!.bytesTransferred
} catch {
log("Error occurred during writing file: \(error.localizedDescription)")
throw NearbyError.protocolError(error.localizedDescription)
}
}
else if (frame.payloadChunk.flags & 1) == 1 {
try fileInfo.fileHandle?.close()
@@ -518,6 +528,9 @@ public class SaveFilesManager {
public func registerFileFinishedDownloading(_ fileURL: URL) {
filesFinishedDownloading.append(fileURL)
filesFinishedDownloadingSinceLastRun.append(fileURL)
// read out EXIF timestamp and manually set file creation date to it
applyEXIFTimestamps(at: fileURL)
}
public func movePendingFilesToTarget() {
@@ -633,6 +646,53 @@ public class SaveFilesManager {
fatalError("Failed to get downloads directory: \(error)")
}
}
/// Returns the EXIF original date of an image file, adjusted to the current time zone.
private func exifOriginalDate(from url: URL) -> Date? {
guard let imageSource = CGImageSourceCreateWithURL(url as CFURL, nil),
let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [CFString: Any],
let exif = properties[kCGImagePropertyExifDictionary] as? [CFString: Any],
let dateString = exif[kCGImagePropertyExifDateTimeOriginal] as? String
else {
return nil
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyy:MM:dd HH:mm:ss"
formatter.timeZone = TimeZone.current // Use the current device time zone
return formatter.date(from: dateString)
}
/// Applies EXIF timestamps to a given file or directory.
private func applyEXIFTimestamps(at url: URL) {
let fm = FileManager.default
var isDir: ObjCBool = false
guard fm.fileExists(atPath: url.path, isDirectory: &isDir) else { return }
if isDir.boolValue {
// It's a directory — enumerate files
if let enumerator = fm.enumerator(at: url, includingPropertiesForKeys: [.isRegularFileKey]) {
for case let fileURL as URL in enumerator {
guard (try? fileURL.resourceValues(forKeys: [.isRegularFileKey]))?.isRegularFile == true else { continue }
applyEXIFTimestamp(to: fileURL)
}
}
} else {
// It's a single file
applyEXIFTimestamp(to: url)
}
}
/// Applies EXIF timestamp (if available) to a single file
private func applyEXIFTimestamp(to fileURL: URL) {
guard let exifDate = exifOriginalDate(from: fileURL) else {
return
}
// Set the "creation date"
try? FileManager.default.setAttributes([.creationDate: exifDate], ofItemAtPath: fileURL.path)
}
}
extension Data {
Loaded 100 of 141 files, more files were not shown because too many files have changed in this diff. Show more