mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-07-06 21:05:20 +02:00
feat: delete photo if it is inserted
This commit is contained in:
@@ -87,6 +87,7 @@
|
|||||||
ECBE529C2C1D94A4006BDB3D /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBE529A2C1D94A4006BDB3D /* CameraView.swift */; };
|
ECBE529C2C1D94A4006BDB3D /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBE529A2C1D94A4006BDB3D /* CameraView.swift */; };
|
||||||
ECBE529E2C1DAB21006BDB3D /* UIImage++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBE529D2C1DAB21006BDB3D /* UIImage++.swift */; };
|
ECBE529E2C1DAB21006BDB3D /* UIImage++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECBE529D2C1DAB21006BDB3D /* UIImage++.swift */; };
|
||||||
ECC995A32C1E8F2800B2699A /* PhotoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC995A22C1E8F2800B2699A /* PhotoItem.swift */; };
|
ECC995A32C1E8F2800B2699A /* PhotoItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC995A22C1E8F2800B2699A /* PhotoItem.swift */; };
|
||||||
|
ECC995A52C1EB4CC00B2699A /* Data++.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECC995A42C1EB4CC00B2699A /* Data++.swift */; };
|
||||||
ECD12A862C19EE3900B96E12 /* ElementObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A852C19EE3900B96E12 /* ElementObject.swift */; };
|
ECD12A862C19EE3900B96E12 /* ElementObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A852C19EE3900B96E12 /* ElementObject.swift */; };
|
||||||
ECD12A8A2C19EFB000B96E12 /* Element.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A892C19EFB000B96E12 /* Element.swift */; };
|
ECD12A8A2C19EFB000B96E12 /* Element.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A892C19EFB000B96E12 /* Element.swift */; };
|
||||||
ECD12A8C2C1AEAA900B96E12 /* PhotoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A8B2C1AEAA900B96E12 /* PhotoObject.swift */; };
|
ECD12A8C2C1AEAA900B96E12 /* PhotoObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = ECD12A8B2C1AEAA900B96E12 /* PhotoObject.swift */; };
|
||||||
@@ -189,6 +190,7 @@
|
|||||||
ECBE529A2C1D94A4006BDB3D /* CameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
|
ECBE529A2C1D94A4006BDB3D /* CameraView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = "<group>"; };
|
||||||
ECBE529D2C1DAB21006BDB3D /* UIImage++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage++.swift"; sourceTree = "<group>"; };
|
ECBE529D2C1DAB21006BDB3D /* UIImage++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage++.swift"; sourceTree = "<group>"; };
|
||||||
ECC995A22C1E8F2800B2699A /* PhotoItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoItem.swift; sourceTree = "<group>"; };
|
ECC995A22C1E8F2800B2699A /* PhotoItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoItem.swift; sourceTree = "<group>"; };
|
||||||
|
ECC995A42C1EB4CC00B2699A /* Data++.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data++.swift"; sourceTree = "<group>"; };
|
||||||
ECD12A852C19EE3900B96E12 /* ElementObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementObject.swift; sourceTree = "<group>"; };
|
ECD12A852C19EE3900B96E12 /* ElementObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementObject.swift; sourceTree = "<group>"; };
|
||||||
ECD12A892C19EFB000B96E12 /* Element.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Element.swift; sourceTree = "<group>"; };
|
ECD12A892C19EFB000B96E12 /* Element.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Element.swift; sourceTree = "<group>"; };
|
||||||
ECD12A8B2C1AEAA900B96E12 /* PhotoObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoObject.swift; sourceTree = "<group>"; };
|
ECD12A8B2C1AEAA900B96E12 /* PhotoObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoObject.swift; sourceTree = "<group>"; };
|
||||||
@@ -514,6 +516,7 @@
|
|||||||
EC3565552BEFC7B300A4E0BF /* NSManagedObject++.swift */,
|
EC3565552BEFC7B300A4E0BF /* NSManagedObject++.swift */,
|
||||||
EC35655B2BF0712A00A4E0BF /* Float++.swift */,
|
EC35655B2BF0712A00A4E0BF /* Float++.swift */,
|
||||||
ECBE529D2C1DAB21006BDB3D /* UIImage++.swift */,
|
ECBE529D2C1DAB21006BDB3D /* UIImage++.swift */,
|
||||||
|
ECC995A42C1EB4CC00B2699A /* Data++.swift */,
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -925,6 +928,7 @@
|
|||||||
ECA738DE2BE610A000A4542E /* ViewPortRenderPass.swift in Sources */,
|
ECA738DE2BE610A000A4542E /* ViewPortRenderPass.swift in Sources */,
|
||||||
EC7F6BEC2BE5E6E300A34A7B /* MemolaApp.swift in Sources */,
|
EC7F6BEC2BE5E6E300A34A7B /* MemolaApp.swift in Sources */,
|
||||||
EC2BEBF82C0F601A005DB0AF /* Node.swift in Sources */,
|
EC2BEBF82C0F601A005DB0AF /* Node.swift in Sources */,
|
||||||
|
ECC995A52C1EB4CC00B2699A /* Data++.swift in Sources */,
|
||||||
ECA738A02BE601E400A4542E /* ViewPortVertex.swift in Sources */,
|
ECA738A02BE601E400A4542E /* ViewPortVertex.swift in Sources */,
|
||||||
ECD12A8A2C19EFB000B96E12 /* Element.swift in Sources */,
|
ECD12A8A2C19EFB000B96E12 /* Element.swift in Sources */,
|
||||||
EC0D14282BF7BF20009BFE5F /* ContextMenuViewModifier.swift in Sources */,
|
EC0D14282BF7BF20009BFE5F /* ContextMenuViewModifier.swift in Sources */,
|
||||||
|
|||||||
@@ -131,42 +131,6 @@ extension Canvas {
|
|||||||
func insertPhoto(at point: CGPoint, photoItem: PhotoItem) {
|
func insertPhoto(at point: CGPoint, photoItem: PhotoItem) {
|
||||||
graphicContext.insertPhoto(at: point, photoItem: photoItem)
|
graphicContext.insertPhoto(at: point, photoItem: photoItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
func bookmarkPhoto(of image: UIImage) -> PhotoItem? {
|
|
||||||
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
|
||||||
let fileManager = FileManager.default
|
|
||||||
guard let directory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
let fileName = "\(UUID().uuidString)-\(Date.now.timeIntervalSince1970)"
|
|
||||||
let folder = directory.appendingPathComponent(canvasID.uriRepresentation().lastPathComponent, conformingTo: .folder)
|
|
||||||
|
|
||||||
if folder.startAccessingSecurityScopedResource(), !fileManager.fileExists(atPath: folder.path()) {
|
|
||||||
do {
|
|
||||||
try fileManager.createDirectory(at: folder, withIntermediateDirectories: true)
|
|
||||||
folder.stopAccessingSecurityScopedResource()
|
|
||||||
} catch {
|
|
||||||
NSLog("[Memola] - \(error.localizedDescription)")
|
|
||||||
folder.stopAccessingSecurityScopedResource()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let file = folder.appendingPathComponent(fileName, conformingTo: .jpeg)
|
|
||||||
do {
|
|
||||||
try data.write(to: file)
|
|
||||||
} catch {
|
|
||||||
NSLog("[Memola] - \(error.localizedDescription)")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var photoBookmark: PhotoItem?
|
|
||||||
do {
|
|
||||||
let bookmark = try file.bookmarkData(options: .minimalBookmark)
|
|
||||||
photoBookmark = PhotoItem(id: file, image: image, bookmark: bookmark)
|
|
||||||
} catch {
|
|
||||||
NSLog("[Memola] - \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
return photoBookmark
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Rendering
|
// MARK: - Rendering
|
||||||
|
|||||||
@@ -59,17 +59,6 @@ final class Photo: @unchecked Sendable, Equatable, Comparable {
|
|||||||
PhotoVertex(x: maxX, y: maxY, textCoord: CGPoint(x: 1, y: 1)),
|
PhotoVertex(x: maxX, y: maxY, textCoord: CGPoint(x: 1, y: 1)),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBookmarkURL() -> URL? {
|
|
||||||
var isStale = false
|
|
||||||
guard let bookmark else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
guard let bookmarkURL = try? URL(resolvingBookmarkData: bookmark, options: .withoutUI, relativeTo: nil, bookmarkDataIsStale: &isStale) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return bookmarkURL
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Photo: Drawable {
|
extension Photo: Drawable {
|
||||||
@@ -78,7 +67,7 @@ extension Photo: Drawable {
|
|||||||
vertexCount = vertices.endIndex
|
vertexCount = vertices.endIndex
|
||||||
vertexBuffer = device.makeBuffer(bytes: vertices, length: vertexCount * MemoryLayout<PhotoVertex>.stride, options: [])
|
vertexBuffer = device.makeBuffer(bytes: vertices, length: vertexCount * MemoryLayout<PhotoVertex>.stride, options: [])
|
||||||
}
|
}
|
||||||
if texture == nil, let url = getBookmarkURL() {
|
if texture == nil, let url = bookmark?.getBookmarkURL() {
|
||||||
texture = Textures.createPhotoTexture(for: url, on: device)
|
texture = Textures.createPhotoTexture(for: url, on: device)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,4 +112,62 @@ public class Tool: NSObject, ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func selectPhoto(_ image: UIImage, for canvasID: NSManagedObjectID) {
|
||||||
|
let photoItem = bookmarkPhoto(of: image, with: canvasID)
|
||||||
|
withAnimation {
|
||||||
|
selectedPhotoItem = photoItem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func bookmarkPhoto(of image: UIImage, with canvasID: NSManagedObjectID) -> PhotoItem? {
|
||||||
|
guard let data = image.jpegData(compressionQuality: 1) else { return nil }
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
guard let directory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let fileName = "\(UUID().uuidString)-\(Date.now.timeIntervalSince1970)"
|
||||||
|
let folder = directory.appendingPathComponent(canvasID.uriRepresentation().lastPathComponent, conformingTo: .folder)
|
||||||
|
|
||||||
|
if folder.startAccessingSecurityScopedResource(), !fileManager.fileExists(atPath: folder.path()) {
|
||||||
|
do {
|
||||||
|
try fileManager.createDirectory(at: folder, withIntermediateDirectories: true)
|
||||||
|
folder.stopAccessingSecurityScopedResource()
|
||||||
|
} catch {
|
||||||
|
NSLog("[Memola] - \(error.localizedDescription)")
|
||||||
|
folder.stopAccessingSecurityScopedResource()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let file = folder.appendingPathComponent(fileName, conformingTo: .jpeg)
|
||||||
|
do {
|
||||||
|
try data.write(to: file)
|
||||||
|
} catch {
|
||||||
|
NSLog("[Memola] - \(error.localizedDescription)")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var photoBookmark: PhotoItem?
|
||||||
|
do {
|
||||||
|
let bookmark = try file.bookmarkData(options: .minimalBookmark)
|
||||||
|
photoBookmark = PhotoItem(id: file, image: image, bookmark: bookmark)
|
||||||
|
} catch {
|
||||||
|
NSLog("[Memola] - \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
return photoBookmark
|
||||||
|
}
|
||||||
|
|
||||||
|
func unselectPhoto() {
|
||||||
|
guard let photoItem = selectedPhotoItem else { return }
|
||||||
|
let fileManager = FileManager.default
|
||||||
|
if let url = photoItem.bookmark.getBookmarkURL() {
|
||||||
|
do {
|
||||||
|
try fileManager.removeItem(at: url)
|
||||||
|
} catch {
|
||||||
|
NSLog("[Memola] - \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withAnimation {
|
||||||
|
selectedPhotoItem = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// Data++.swift
|
||||||
|
// Memola
|
||||||
|
//
|
||||||
|
// Created by Dscyre Scotti on 6/16/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension Data {
|
||||||
|
func getBookmarkURL() -> URL? {
|
||||||
|
var isStale = false
|
||||||
|
guard let bookmarkURL = try? URL(resolvingBookmarkData: self, options: .withoutUI, relativeTo: nil, bookmarkDataIsStale: &isStale) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return bookmarkURL
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,9 +26,7 @@ struct PhotoPreview: View {
|
|||||||
.cornerRadius(5)
|
.cornerRadius(5)
|
||||||
.overlay(alignment: .topLeading) {
|
.overlay(alignment: .topLeading) {
|
||||||
Button {
|
Button {
|
||||||
withAnimation {
|
tool.unselectPhoto()
|
||||||
tool.selectedPhotoItem = nil
|
|
||||||
}
|
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "xmark.circle.fill")
|
Image(systemName: "xmark.circle.fill")
|
||||||
.font(.title2)
|
.font(.title2)
|
||||||
|
|||||||
@@ -61,10 +61,7 @@ struct Toolbar: View {
|
|||||||
Task {
|
Task {
|
||||||
let data = try? await newValue?.loadTransferable(type: Data.self)
|
let data = try? await newValue?.loadTransferable(type: Data.self)
|
||||||
if let data, let image = UIImage(data: data) {
|
if let data, let image = UIImage(data: data) {
|
||||||
let photoItem = canvas.bookmarkPhoto(of: image)
|
tool.selectPhoto(image, for: canvas.canvasID)
|
||||||
withAnimation {
|
|
||||||
tool.selectedPhotoItem = photoItem
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
photosPickerItem = nil
|
photosPickerItem = nil
|
||||||
}
|
}
|
||||||
@@ -75,7 +72,7 @@ struct Toolbar: View {
|
|||||||
tool.selectedPhotoItem?.image
|
tool.selectedPhotoItem?.image
|
||||||
} set: { image in
|
} set: { image in
|
||||||
guard let image else { return }
|
guard let image else { return }
|
||||||
tool.selectedPhotoItem = canvas.bookmarkPhoto(of: image)
|
tool.selectPhoto(image, for: canvas.canvasID)
|
||||||
}
|
}
|
||||||
CameraView(image: image, canvas: canvas)
|
CameraView(image: image, canvas: canvas)
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
|||||||
Reference in New Issue
Block a user