mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-05-13 11:20:18 +02:00
feat: remove lock button
This commit is contained in:
@@ -32,7 +32,6 @@ final class Canvas: ObservableObject, Identifiable, @unchecked Sendable {
|
|||||||
|
|
||||||
@Published var state: State = .initial
|
@Published var state: State = .initial
|
||||||
@Published var zoomScale: CGFloat = .zero
|
@Published var zoomScale: CGFloat = .zero
|
||||||
@Published var locksCanvas: Bool = false
|
|
||||||
|
|
||||||
@Published var gridMode: GridMode = .point
|
@Published var gridMode: GridMode = .point
|
||||||
|
|
||||||
|
|||||||
@@ -260,11 +260,6 @@ extension CanvasViewController {
|
|||||||
self?.zoomChanged(zoomScale)
|
self?.zoomChanged(zoomScale)
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.store(in: &cancellables)
|
||||||
canvas.$locksCanvas
|
|
||||||
.sink { [weak self] state in
|
|
||||||
self?.lockModeChanged(state)
|
|
||||||
}
|
|
||||||
.store(in: &cancellables)
|
|
||||||
canvas.$gridMode
|
canvas.$gridMode
|
||||||
.delay(for: .milliseconds(100), scheduler: DispatchQueue.main)
|
.delay(for: .milliseconds(100), scheduler: DispatchQueue.main)
|
||||||
.sink { [weak self] mode in
|
.sink { [weak self] mode in
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ struct DashboardView: View {
|
|||||||
MemosView()
|
MemosView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.fullScreenCover(item: $memoManager.memo) { memo in
|
.fullScreenCover(item: $memoManager.memoObject) { memo in
|
||||||
MemoView(memo: memo)
|
MemoView(memo: memo)
|
||||||
.onDisappear {
|
.onDisappear {
|
||||||
withPersistence(\.viewContext) { context in
|
withPersistence(\.viewContext) { context in
|
||||||
|
|||||||
@@ -234,7 +234,6 @@ struct ElementToolbar: View {
|
|||||||
.contentShape(.rect(cornerRadius: 8))
|
.contentShape(.rect(cornerRadius: 8))
|
||||||
}
|
}
|
||||||
.hoverEffect(.lift)
|
.hoverEffect(.lift)
|
||||||
.buttonStyle(.plain)
|
|
||||||
#endif
|
#endif
|
||||||
PhotosPicker(selection: $photosPickerItem, matching: .images, preferredItemEncoding: .compatible) {
|
PhotosPicker(selection: $photosPickerItem, matching: .images, preferredItemEncoding: .compatible) {
|
||||||
Image(systemName: "photo.fill.on.rectangle.fill")
|
Image(systemName: "photo.fill.on.rectangle.fill")
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ struct MemoView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.overlay(alignment: .bottom) {
|
.overlay(alignment: .bottom) {
|
||||||
if tool.selection != .hand && !canvas.locksCanvas {
|
if tool.selection != .hand {
|
||||||
Button {
|
Button {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
tool.selectTool(.hand)
|
tool.selectTool(.hand)
|
||||||
@@ -135,72 +135,70 @@ struct MemoView: View {
|
|||||||
let lowerBound: CGFloat = 10
|
let lowerBound: CGFloat = 10
|
||||||
let zoomScale: CGFloat = (((canvas.zoomScale - canvas.minimumZoomScale) * (upperBound - lowerBound) / (canvas.maximumZoomScale - canvas.minimumZoomScale)) + lowerBound).rounded()
|
let zoomScale: CGFloat = (((canvas.zoomScale - canvas.minimumZoomScale) * (upperBound - lowerBound) / (canvas.maximumZoomScale - canvas.minimumZoomScale)) + lowerBound).rounded()
|
||||||
let zoomScales: [Int] = [400, 200, 100, 75, 50, 25, 10]
|
let zoomScales: [Int] = [400, 200, 100, 75, 50, 25, 10]
|
||||||
if !canvas.locksCanvas {
|
#if os(macOS)
|
||||||
#if os(macOS)
|
Menu {
|
||||||
Menu {
|
ForEach(zoomScales, id: \.self) { scale in
|
||||||
ForEach(zoomScales, id: \.self) { scale in
|
Button {
|
||||||
Button {
|
let zoomScale = ((CGFloat(scale) - lowerBound) * (canvas.maximumZoomScale - canvas.minimumZoomScale) / (upperBound - lowerBound)) + canvas.minimumZoomScale
|
||||||
let zoomScale = ((CGFloat(scale) - lowerBound) * (canvas.maximumZoomScale - canvas.minimumZoomScale) / (upperBound - lowerBound)) + canvas.minimumZoomScale
|
canvas.zoomPublisher.send(zoomScale)
|
||||||
canvas.zoomPublisher.send(zoomScale)
|
} label: {
|
||||||
} label: {
|
Label {
|
||||||
Label {
|
Text(scale, format: .percent)
|
||||||
Text(scale, format: .percent)
|
} icon: {
|
||||||
} icon: {
|
if CGFloat(scale) == zoomScale {
|
||||||
if CGFloat(scale) == zoomScale {
|
Image(systemName: "checkmark")
|
||||||
Image(systemName: "checkmark")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.font(.headline)
|
|
||||||
}
|
}
|
||||||
|
.font(.headline)
|
||||||
}
|
}
|
||||||
} label: {
|
|
||||||
Text(zoomScale / 100, format: .percent)
|
|
||||||
.font(.subheadline)
|
|
||||||
.frame(height: size)
|
|
||||||
.clipShape(.rect(cornerRadius: 8))
|
|
||||||
.contentShape(.rect(cornerRadius: 8))
|
|
||||||
}
|
}
|
||||||
.menuIndicator(.hidden)
|
} label: {
|
||||||
.frame(width: 50, height: size)
|
Text(zoomScale / 100, format: .percent)
|
||||||
.padding(.leading, 12)
|
.font(.subheadline)
|
||||||
.background(.regularMaterial)
|
.frame(height: size)
|
||||||
.clipShape(.rect(cornerRadius: 8))
|
.clipShape(.rect(cornerRadius: 8))
|
||||||
.contentShape(.rect(cornerRadius: 8))
|
.contentShape(.rect(cornerRadius: 8))
|
||||||
.menuStyle(.borderlessButton)
|
|
||||||
.transition(.move(edge: .bottom).combined(with: .blurReplace))
|
|
||||||
.padding(10)
|
|
||||||
#else
|
|
||||||
Menu {
|
|
||||||
ForEach(zoomScales, id: \.self) { scale in
|
|
||||||
Button {
|
|
||||||
let zoomScale = ((CGFloat(scale) - lowerBound) * (canvas.maximumZoomScale - canvas.minimumZoomScale) / (upperBound - lowerBound)) + canvas.minimumZoomScale
|
|
||||||
canvas.zoomPublisher.send(zoomScale)
|
|
||||||
} label: {
|
|
||||||
Label {
|
|
||||||
Text(scale, format: .percent)
|
|
||||||
} icon: {
|
|
||||||
if CGFloat(scale) == zoomScale {
|
|
||||||
Image(systemName: "checkmark")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.font(.headline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Text(zoomScale / 100, format: .percent)
|
|
||||||
.frame(width: 45)
|
|
||||||
.font(.subheadline)
|
|
||||||
.padding(.horizontal, size / 2.5)
|
|
||||||
.frame(height: size)
|
|
||||||
.background(.regularMaterial)
|
|
||||||
.clipShape(.rect(cornerRadius: 8))
|
|
||||||
.contentShape(.rect(cornerRadius: 8))
|
|
||||||
.padding(10)
|
|
||||||
}
|
|
||||||
.hoverEffect(.lift)
|
|
||||||
.transition(.move(edge: .bottom).combined(with: .blurReplace))
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
.menuIndicator(.hidden)
|
||||||
|
.frame(width: 50, height: size)
|
||||||
|
.padding(.leading, 12)
|
||||||
|
.background(.regularMaterial)
|
||||||
|
.clipShape(.rect(cornerRadius: 8))
|
||||||
|
.contentShape(.rect(cornerRadius: 8))
|
||||||
|
.menuStyle(.borderlessButton)
|
||||||
|
.transition(.move(edge: .bottom).combined(with: .blurReplace))
|
||||||
|
.padding(10)
|
||||||
|
#else
|
||||||
|
Menu {
|
||||||
|
ForEach(zoomScales, id: \.self) { scale in
|
||||||
|
Button {
|
||||||
|
let zoomScale = ((CGFloat(scale) - lowerBound) * (canvas.maximumZoomScale - canvas.minimumZoomScale) / (upperBound - lowerBound)) + canvas.minimumZoomScale
|
||||||
|
canvas.zoomPublisher.send(zoomScale)
|
||||||
|
} label: {
|
||||||
|
Label {
|
||||||
|
Text(scale, format: .percent)
|
||||||
|
} icon: {
|
||||||
|
if CGFloat(scale) == zoomScale {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.font(.headline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Text(zoomScale / 100, format: .percent)
|
||||||
|
.frame(width: 45)
|
||||||
|
.font(.subheadline)
|
||||||
|
.padding(.horizontal, size / 2.5)
|
||||||
|
.frame(height: size)
|
||||||
|
.background(.regularMaterial)
|
||||||
|
.clipShape(.rect(cornerRadius: 8))
|
||||||
|
.contentShape(.rect(cornerRadius: 8))
|
||||||
|
.padding(10)
|
||||||
|
}
|
||||||
|
.hoverEffect(.lift)
|
||||||
|
.transition(.move(edge: .bottom).combined(with: .blurReplace))
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadingIndicator(_ title: String) -> some View {
|
func loadingIndicator(_ title: String) -> some View {
|
||||||
|
|||||||
@@ -29,71 +29,46 @@ struct PenDock: View {
|
|||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
ZStack(alignment: .bottomTrailing) {
|
VStack(alignment: .trailing) {
|
||||||
if !canvas.locksCanvas {
|
penPropertyTool
|
||||||
VStack(alignment: .trailing) {
|
penItemList
|
||||||
penPropertyTool
|
|
||||||
penItemList
|
|
||||||
}
|
|
||||||
.fixedSize()
|
|
||||||
.frame(maxHeight: .infinity)
|
|
||||||
.padding(10)
|
|
||||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
|
||||||
}
|
|
||||||
lockButton
|
|
||||||
.padding(10)
|
|
||||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
|
||||||
}
|
}
|
||||||
|
.fixedSize()
|
||||||
|
.frame(maxHeight: .infinity)
|
||||||
|
.padding(10)
|
||||||
|
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
||||||
#else
|
#else
|
||||||
if horizontalSizeClass == .regular {
|
if horizontalSizeClass == .regular {
|
||||||
ZStack(alignment: .bottomTrailing) {
|
VStack(alignment: .trailing) {
|
||||||
if !canvas.locksCanvas {
|
penPropertyTool
|
||||||
VStack(alignment: .trailing) {
|
penItemList
|
||||||
penPropertyTool
|
|
||||||
penItemList
|
|
||||||
}
|
|
||||||
.fixedSize()
|
|
||||||
.frame(maxHeight: .infinity)
|
|
||||||
.padding(10)
|
|
||||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
|
||||||
}
|
|
||||||
lockButton
|
|
||||||
.padding(10)
|
|
||||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
|
||||||
}
|
}
|
||||||
|
.fixedSize()
|
||||||
|
.frame(maxHeight: .infinity)
|
||||||
|
.padding(10)
|
||||||
|
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
||||||
} else {
|
} else {
|
||||||
GeometryReader { proxy in
|
GeometryReader { proxy in
|
||||||
ZStack(alignment: .bottomTrailing) {
|
HStack(alignment: .bottom, spacing: 10) {
|
||||||
if !canvas.locksCanvas {
|
newPenButton
|
||||||
GeometryReader { proxy in
|
.frame(height: height * factor - 18)
|
||||||
HStack(alignment: .bottom, spacing: 10) {
|
compactPenItemList
|
||||||
newPenButton
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.frame(height: height * factor - 18)
|
compactPenPropertyTool
|
||||||
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)
|
|
||||||
}
|
|
||||||
.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))
|
|
||||||
}
|
}
|
||||||
|
.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))
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -331,7 +306,6 @@ struct PenDock: View {
|
|||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: 8)
|
||||||
.fill(.regularMaterial)
|
.fill(.regularMaterial)
|
||||||
}
|
}
|
||||||
.transition(.move(edge: .trailing).combined(with: .blurReplace))
|
|
||||||
} else {
|
} else {
|
||||||
Color.clear
|
Color.clear
|
||||||
.frame(width: width * factor - 18, height: 50)
|
.frame(width: width * factor - 18, height: 50)
|
||||||
@@ -546,26 +520,6 @@ struct PenDock: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var lockButton: some View {
|
|
||||||
Button {
|
|
||||||
withAnimation {
|
|
||||||
canvas.locksCanvas.toggle()
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Image(systemName: canvas.locksCanvas ? "lock.fill" : "lock.open.fill")
|
|
||||||
.frame(width: size, height: size)
|
|
||||||
.background(.regularMaterial)
|
|
||||||
.clipShape(.rect(cornerRadius: 8))
|
|
||||||
.contentShape(.rect(cornerRadius: 8))
|
|
||||||
}
|
|
||||||
#if os(iOS)
|
|
||||||
.hoverEffect(.lift)
|
|
||||||
#else
|
|
||||||
.buttonStyle(.plain)
|
|
||||||
#endif
|
|
||||||
.contentTransition(.symbolEffect(.replace))
|
|
||||||
}
|
|
||||||
|
|
||||||
func createNewPen() {
|
func createNewPen() {
|
||||||
let pen = PenObject.createObject(\.viewContext, penStyle: .marker)
|
let pen = PenObject.createObject(\.viewContext, penStyle: .marker)
|
||||||
var selectedPen = tool.selectedPen
|
var selectedPen = tool.selectedPen
|
||||||
|
|||||||
@@ -35,26 +35,20 @@ struct Toolbar: View {
|
|||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: 5) {
|
HStack(spacing: 5) {
|
||||||
HStack(spacing: 5) {
|
HStack(spacing: 5) {
|
||||||
if !canvas.locksCanvas {
|
closeButton
|
||||||
closeButton
|
titleField
|
||||||
titleField
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
if !canvas.locksCanvas {
|
ElementToolbar(size: size, tool: tool, canvas: canvas)
|
||||||
ElementToolbar(size: size, tool: tool, canvas: canvas)
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
if !canvas.locksCanvas, horizontalSizeClass == .regular {
|
if horizontalSizeClass == .regular {
|
||||||
ElementToolbar(size: size, tool: tool, canvas: canvas)
|
ElementToolbar(size: size, tool: tool, canvas: canvas)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
HStack(spacing: 5) {
|
HStack(spacing: 5) {
|
||||||
if !canvas.locksCanvas {
|
gridModeControl
|
||||||
gridModeControl
|
historyControl
|
||||||
historyControl
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .trailing)
|
.frame(maxWidth: .infinity, alignment: .trailing)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user