mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-03-27 03:41:19 +01:00
feat: open memo object over dasboardview instead of new window
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
EC2BEBF82C0F601A005DB0AF /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2BEBF72C0F601A005DB0AF /* Node.swift */; };
|
||||
EC35655A2BF060D900A4E0BF /* Quad.metal in Sources */ = {isa = PBXBuildFile; fileRef = EC3565592BF060D900A4E0BF /* Quad.metal */; };
|
||||
EC37FB122C1B2DD90008D976 /* ToolSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC37FB112C1B2DD90008D976 /* ToolSelection.swift */; };
|
||||
EC3D67CC2C3AAD5E00359400 /* MemoManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3D67CB2C3AAD5E00359400 /* MemoManager.swift */; };
|
||||
EC42F7852C25267000E86E96 /* ElementGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC42F7842C25267000E86E96 /* ElementGroup.swift */; };
|
||||
EC4538892BEBCAE000A86FEC /* Quad.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC4538882BEBCAE000A86FEC /* Quad.swift */; };
|
||||
EC5050072BF65CED00B4D86E /* PenDropDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC5050062BF65CED00B4D86E /* PenDropDelegate.swift */; };
|
||||
@@ -151,6 +152,7 @@
|
||||
EC2BEBF72C0F601A005DB0AF /* Node.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Node.swift; sourceTree = "<group>"; };
|
||||
EC3565592BF060D900A4E0BF /* Quad.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Quad.metal; sourceTree = "<group>"; };
|
||||
EC37FB112C1B2DD90008D976 /* ToolSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolSelection.swift; sourceTree = "<group>"; };
|
||||
EC3D67CB2C3AAD5E00359400 /* MemoManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemoManager.swift; sourceTree = "<group>"; };
|
||||
EC42F7842C25267000E86E96 /* ElementGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ElementGroup.swift; sourceTree = "<group>"; };
|
||||
EC4538882BEBCAE000A86FEC /* Quad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Quad.swift; sourceTree = "<group>"; };
|
||||
EC5050062BF65CED00B4D86E /* PenDropDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PenDropDelegate.swift; sourceTree = "<group>"; };
|
||||
@@ -279,6 +281,7 @@
|
||||
EC01511C2C305C99008A115E /* Dashboard */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EC3D67CB2C3AAD5E00359400 /* MemoManager.swift */,
|
||||
EC01511D2C305CA9008A115E /* DashboardView.swift */,
|
||||
);
|
||||
path = Dashboard;
|
||||
@@ -1021,6 +1024,7 @@
|
||||
ECA738A82BE6025900A4542E /* GraphicUniforms.swift in Sources */,
|
||||
EC01511E2C305CA9008A115E /* DashboardView.swift in Sources */,
|
||||
EC8F54AE2C2AF5A4001C7C74 /* LineGridVertex.swift in Sources */,
|
||||
EC3D67CC2C3AAD5E00359400 /* MemoManager.swift in Sources */,
|
||||
EC5E83902BFDB69C00261D9C /* MovingAverage.swift in Sources */,
|
||||
ECFA15262BEF224900455818 /* StrokeObject.swift in Sources */,
|
||||
ECA738FC2BE61C5200A4542E /* Persistence.swift in Sources */,
|
||||
|
||||
@@ -29,19 +29,7 @@ struct MemolaApp: App {
|
||||
.defaultPosition(.center)
|
||||
.windowResizability(.contentSize)
|
||||
.defaultSize(width: 1200, height: 800)
|
||||
#endif
|
||||
WindowGroup(id: "memo-view", for: URL.self) { url in
|
||||
if let url = url.wrappedValue, let memo = Persistence.loadMemo(of: url) {
|
||||
MemoView(memo: memo)
|
||||
#if os(macOS)
|
||||
.frame(minWidth: 1000, minHeight: 600)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if os(macOS)
|
||||
.defaultPosition(.center)
|
||||
.windowResizability(.contentSize)
|
||||
.defaultSize(width: 1200, height: 800)
|
||||
.windowToolbarStyle(.unifiedCompact)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,38 +10,54 @@ import SwiftUI
|
||||
struct DashboardView: View {
|
||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass
|
||||
|
||||
#if os(iOS)
|
||||
@State var memo: MemoObject?
|
||||
#endif
|
||||
@StateObject var memoManager: MemoManager = .shared
|
||||
|
||||
@State var sidebarItem: SidebarItem? = .memos
|
||||
|
||||
@Namespace var namespace
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
NavigationSplitView {
|
||||
Sidebar(sidebarItem: $sidebarItem, horizontalSizeClass: horizontalSizeClass)
|
||||
} detail: {
|
||||
switch sidebarItem {
|
||||
case .memos:
|
||||
#if os(macOS)
|
||||
MemosView()
|
||||
#else
|
||||
MemosView(memo: $memo)
|
||||
#endif
|
||||
case .trash:
|
||||
#if os(macOS)
|
||||
TrashView(sidebarItem: $sidebarItem)
|
||||
#else
|
||||
TrashView(memo: $memo, sidebarItem: $sidebarItem)
|
||||
#endif
|
||||
default:
|
||||
#if os(macOS)
|
||||
MemosView()
|
||||
#else
|
||||
MemosView(memo: $memo)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if os(iOS)
|
||||
.fullScreenCover(item: $memo) { memo in
|
||||
.toolbar(memoManager.memoObject == nil ? .visible : .hidden, for: .windowToolbar)
|
||||
.toolbarBackground(memoManager.memoObject == nil ? .clear : Color(nsColor: .windowBackgroundColor), for: .windowToolbar)
|
||||
.overlay {
|
||||
if let memo = memoManager.memoObject {
|
||||
MemoView(memo: memo)
|
||||
.onDisappear {
|
||||
withPersistence(\.viewContext) { context in
|
||||
try context.saveIfNeeded()
|
||||
context.refreshAllObjects()
|
||||
}
|
||||
}
|
||||
.transition(.move(edge: .bottom))
|
||||
}
|
||||
}
|
||||
#else
|
||||
NavigationSplitView {
|
||||
Sidebar(sidebarItem: $sidebarItem, horizontalSizeClass: horizontalSizeClass)
|
||||
} detail: {
|
||||
switch sidebarItem {
|
||||
case .memos:
|
||||
MemosView()
|
||||
case .trash:
|
||||
TrashView(sidebarItem: $sidebarItem)
|
||||
default:
|
||||
MemosView()
|
||||
}
|
||||
}
|
||||
.fullScreenCover(item: $memoManager.memo) { memo in
|
||||
MemoView(memo: memo)
|
||||
.onDisappear {
|
||||
withPersistence(\.viewContext) { context in
|
||||
@@ -50,7 +66,6 @@ struct DashboardView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
37
Memola/Features/Dashboard/Dashboard/MemoManager.swift
Normal file
37
Memola/Features/Dashboard/Dashboard/MemoManager.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// MemoManager.swift
|
||||
// Memola
|
||||
//
|
||||
// Created by Dscyre Scotti on 7/7/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Foundation
|
||||
|
||||
class MemoManager: ObservableObject {
|
||||
static let shared: MemoManager = .init()
|
||||
|
||||
@Published var memoObject: MemoObject?
|
||||
|
||||
private init() { }
|
||||
|
||||
func openMemo(_ memoObject: MemoObject?) {
|
||||
#if os(macOS)
|
||||
withAnimation(.easeOut) {
|
||||
self.memoObject = memoObject
|
||||
}
|
||||
#else
|
||||
self.memoObject = memoObject
|
||||
#endif
|
||||
}
|
||||
|
||||
func closeMemo() {
|
||||
#if os(macOS)
|
||||
withAnimation(.easeOut) {
|
||||
self.memoObject = nil
|
||||
}
|
||||
#else
|
||||
self.memoObject = nil
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct MemosView: View {
|
||||
#if os(macOS)
|
||||
@Environment(\.openWindow) var openWindow
|
||||
#endif
|
||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass
|
||||
|
||||
@FetchRequest var memoObjects: FetchedResults<MemoObject>
|
||||
@@ -18,10 +15,6 @@ struct MemosView: View {
|
||||
@State var query: String = ""
|
||||
@State var currentDate: Date = .now
|
||||
|
||||
#if os(iOS)
|
||||
@Binding var memo: MemoObject?
|
||||
#endif
|
||||
|
||||
@AppStorage("memola.memo-objects.memos.sort") var sort: Sort = .recent
|
||||
@AppStorage("memola.memo-objects.memos.filter") var filter: Filter = .none
|
||||
|
||||
@@ -31,7 +24,6 @@ struct MemosView: View {
|
||||
query.isEmpty ? .memoEmpty : .memoNotFound
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
init() {
|
||||
let standard = UserDefaults.standard
|
||||
var descriptors: [SortDescriptor<MemoObject>] = []
|
||||
@@ -45,22 +37,6 @@ struct MemosView: View {
|
||||
let predicate = NSCompoundPredicate(type: .and, subpredicates: predicates)
|
||||
_memoObjects = FetchRequest(sortDescriptors: descriptors, predicate: predicate)
|
||||
}
|
||||
#else
|
||||
init(memo: Binding<MemoObject?>) {
|
||||
_memo = memo
|
||||
let standard = UserDefaults.standard
|
||||
var descriptors: [SortDescriptor<MemoObject>] = []
|
||||
var predicates: [NSPredicate] = [NSPredicate(format: "isTrash = NO")]
|
||||
let sort = Sort(rawValue: standard.value(forKey: "memola.memo-objects.memos.sort") as? String ?? "") ?? .recent
|
||||
let filter = Filter(rawValue: standard.value(forKey: "memola.memo-objects.memos.filter") as? String ?? "") ?? .none
|
||||
if filter == .favorites {
|
||||
predicates.append(NSPredicate(format: "isFavorite = YES"))
|
||||
}
|
||||
descriptors = sort.memoSortDescriptors
|
||||
let predicate = NSCompoundPredicate(type: .and, subpredicates: predicates)
|
||||
_memoObjects = FetchRequest(sortDescriptors: descriptors, predicate: predicate)
|
||||
}
|
||||
#endif
|
||||
|
||||
var body: some View {
|
||||
MemoGrid(memoObjects: memoObjects, placeholder: placeholder) { memoObject, cellWidth in
|
||||
@@ -273,11 +249,7 @@ struct MemosView: View {
|
||||
}
|
||||
|
||||
func openMemo(for memo: MemoObject) {
|
||||
#if os(macOS)
|
||||
openWindow(id: "memo-view", value: memo.objectID.uriRepresentation())
|
||||
#else
|
||||
self.memo = memo
|
||||
#endif
|
||||
MemoManager.shared.openMemo(memo)
|
||||
}
|
||||
|
||||
func updatePredicate() {
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TrashView: View {
|
||||
#if os(macOS)
|
||||
@Environment(\.openWindow) var openWindow
|
||||
#endif
|
||||
@Environment(\.horizontalSizeClass) var horizontalSizeClass
|
||||
|
||||
@FetchRequest var memoObjects: FetchedResults<MemoObject>
|
||||
@@ -19,31 +16,18 @@ struct TrashView: View {
|
||||
@State var restoredMemo: MemoObject?
|
||||
@State var deletedMemo: MemoObject?
|
||||
|
||||
#if os(iOS)
|
||||
@Binding var memo: MemoObject?
|
||||
#endif
|
||||
@Binding var sidebarItem: SidebarItem?
|
||||
|
||||
var placeholder: Placeholder.Info {
|
||||
query.isEmpty ? .trashEmpty : .trashNotFound
|
||||
}
|
||||
|
||||
#if os(macOS)
|
||||
init(sidebarItem: Binding<SidebarItem?>) {
|
||||
_sidebarItem = sidebarItem
|
||||
let descriptors = [SortDescriptor(\MemoObject.deletedAt, order: .reverse)]
|
||||
let predicate = NSPredicate(format: "isTrash = YES")
|
||||
_memoObjects = FetchRequest(sortDescriptors: descriptors, predicate: predicate)
|
||||
}
|
||||
#else
|
||||
init(memo: Binding<MemoObject?>, sidebarItem: Binding<SidebarItem?>) {
|
||||
_memo = memo
|
||||
_sidebarItem = sidebarItem
|
||||
let descriptors = [SortDescriptor(\MemoObject.deletedAt, order: .reverse)]
|
||||
let predicate = NSPredicate(format: "isTrash = YES")
|
||||
_memoObjects = FetchRequest(sortDescriptors: descriptors, predicate: predicate)
|
||||
}
|
||||
#endif
|
||||
|
||||
var body: some View {
|
||||
let restoresMemo = Binding<Bool> {
|
||||
@@ -161,11 +145,7 @@ struct TrashView: View {
|
||||
restoreMemo(for: memo)
|
||||
self.sidebarItem = .memos
|
||||
if let memo {
|
||||
#if os(macOS)
|
||||
openWindow(id: "memo-view", value: memo.objectID.uriRepresentation())
|
||||
#else
|
||||
self.memo = memo
|
||||
#endif
|
||||
MemoManager.shared.openMemo(memo)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -156,11 +156,13 @@ struct ElementToolbar: View {
|
||||
.buttonStyle(.plain)
|
||||
#endif
|
||||
.background {
|
||||
#if os(iOS)
|
||||
if tool.selection == .photo {
|
||||
Color.accentColor
|
||||
.clipShape(.rect(cornerRadius: 8))
|
||||
.matchedGeometryEffect(id: "element.toolbar.bg", in: namespace)
|
||||
}
|
||||
#endif
|
||||
if tool.selection != .photo {
|
||||
Color.clear
|
||||
.matchedGeometryEffect(id: "element.toolbar.photo.options", in: namespace)
|
||||
@@ -172,13 +174,6 @@ struct ElementToolbar: View {
|
||||
.transition(.blurReplace.animation(.easeIn(duration: 0.1)))
|
||||
}
|
||||
}
|
||||
// .background {
|
||||
// if tool.selection == .photo {
|
||||
// RoundedRectangle(cornerRadius: 8)
|
||||
// .fill(Color.white.tertiary)
|
||||
// .transition(.move(edge: .leading).combined(with: .opacity).animation(.easeIn(duration: 0.1)))
|
||||
// }
|
||||
// }
|
||||
}
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
@@ -228,6 +223,7 @@ struct ElementToolbar: View {
|
||||
|
||||
var photoOption: some View {
|
||||
HStack(spacing: 0) {
|
||||
#if os(iOS)
|
||||
Button {
|
||||
openCamera()
|
||||
} label: {
|
||||
@@ -237,9 +233,7 @@ struct ElementToolbar: View {
|
||||
.clipShape(.rect(cornerRadius: 8))
|
||||
.contentShape(.rect(cornerRadius: 8))
|
||||
}
|
||||
#if os(iOS)
|
||||
.hoverEffect(.lift)
|
||||
#else
|
||||
.buttonStyle(.plain)
|
||||
#endif
|
||||
PhotosPicker(selection: $photosPickerItem, matching: .images, preferredItemEncoding: .compatible) {
|
||||
|
||||
@@ -15,10 +15,10 @@ struct MemoView: View {
|
||||
@StateObject var canvas: Canvas
|
||||
@StateObject var history: History
|
||||
|
||||
@State var memo: MemoObject
|
||||
@State var title: String
|
||||
@FocusState var textFieldState: Bool
|
||||
|
||||
let memo: MemoObject
|
||||
let size: CGFloat = 32
|
||||
|
||||
init(memo: MemoObject) {
|
||||
|
||||
@@ -62,35 +62,37 @@ struct PenDock: View {
|
||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
||||
}
|
||||
} else {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
if !canvas.locksCanvas {
|
||||
GeometryReader { proxy in
|
||||
HStack(alignment: .bottom, spacing: 10) {
|
||||
newPenButton
|
||||
.frame(height: height * factor - 18)
|
||||
compactPenItemList
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
compactPenPropertyTool
|
||||
GeometryReader { proxy in
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
if !canvas.locksCanvas {
|
||||
GeometryReader { proxy in
|
||||
HStack(alignment: .bottom, spacing: 10) {
|
||||
newPenButton
|
||||
.frame(height: height * factor - 18)
|
||||
compactPenItemList
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
compactPenPropertyTool
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.clipped()
|
||||
.background(alignment: .bottom) {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(.regularMaterial)
|
||||
.frame(height: height * factor - 18)
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.bottom, 20)
|
||||
.frame(maxWidth: min(proxy.size.height, proxy.size.width), maxHeight: .infinity, alignment: .bottom)
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.clipped()
|
||||
.background(alignment: .bottom) {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.fill(.regularMaterial)
|
||||
.frame(height: height * factor - 18)
|
||||
}
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.bottom, 20)
|
||||
.frame(maxWidth: min(proxy.size.height, proxy.size.width), maxHeight: .infinity, alignment: .bottom)
|
||||
.frame(maxWidth: .infinity)
|
||||
.transition(.move(edge: .bottom).combined(with: .blurReplace))
|
||||
}
|
||||
.transition(.move(edge: .bottom).combined(with: .blurReplace))
|
||||
lockButton
|
||||
.frame(maxWidth: .infinity, alignment: .bottomTrailing)
|
||||
.padding(10)
|
||||
.offset(y: canvas.locksCanvas || proxy.size.width > proxy.size.height ? 0 : -(height * factor - size + 30))
|
||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
||||
}
|
||||
lockButton
|
||||
.frame(maxWidth: .infinity, alignment: .bottomTrailing)
|
||||
.padding(10)
|
||||
.offset(y: canvas.locksCanvas ? 0 : -(height * factor - size + 30))
|
||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -17,11 +17,11 @@ struct Toolbar: View {
|
||||
@ObservedObject var history: History
|
||||
|
||||
@State var title: String
|
||||
@State var memo: MemoObject
|
||||
|
||||
@FocusState var textFieldState: Bool
|
||||
|
||||
let size: CGFloat
|
||||
let memo: MemoObject
|
||||
|
||||
init(size: CGFloat, memo: MemoObject, tool: Tool, canvas: Canvas, history: History) {
|
||||
self.size = size
|
||||
@@ -190,7 +190,11 @@ struct Toolbar: View {
|
||||
|
||||
func closeMemo() {
|
||||
canvas.save(for: memo) {
|
||||
#if os(macOS)
|
||||
MemoManager.shared.closeMemo()
|
||||
#else
|
||||
dismiss()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user