Files
Memola/Memola/Features/Memo/Toolbar/Toolbar.swift
T
2024-07-02 02:37:37 +07:00

169 lines
5.1 KiB
Swift

//
// Toolbar.swift
// Memola
//
// Created by Dscyre Scotti on 5/19/24.
//
import SwiftUI
import Foundation
struct Toolbar: View {
@Environment(\.dismiss) var dismiss
@Environment(\.horizontalSizeClass) var horizontalSizeClass
@ObservedObject var tool: Tool
@ObservedObject var canvas: Canvas
@ObservedObject var history: History
@State var title: String
@State var memo: MemoObject
@FocusState var textFieldState: Bool
let size: CGFloat
init(size: CGFloat, memo: MemoObject, tool: Tool, canvas: Canvas, history: History) {
self.size = size
self.memo = memo
self.tool = tool
self.canvas = canvas
self.history = history
self.title = memo.title
}
var body: some View {
HStack(spacing: 5) {
HStack(spacing: 5) {
if !canvas.locksCanvas {
closeButton
titleField
}
}
.frame(maxWidth: .infinity, alignment: .leading)
if !canvas.locksCanvas, horizontalSizeClass == .regular {
ElementToolbar(size: size, tool: tool, canvas: canvas)
}
HStack(spacing: 5) {
if !canvas.locksCanvas {
gridModeControl
historyControl
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
}
.font(.subheadline)
.padding(10)
}
var closeButton: some View {
Button {
closeMemo()
} label: {
Image(systemName: "xmark")
.contentShape(.circle)
.frame(width: size, height: size)
.background(.regularMaterial)
.clipShape(.rect(cornerRadius: 8))
}
.hoverEffect(.lift)
.disabled(textFieldState)
.transition(.move(edge: .top).combined(with: .blurReplace))
}
var titleField: some View {
TextField("", text: $title)
.focused($textFieldState)
.textFieldStyle(.plain)
.padding(.horizontal, size / 2.5)
.frame(width: horizontalSizeClass == .compact ? 100 : 140, height: size)
.background(.regularMaterial)
.clipShape(.rect(cornerRadius: 8))
.onChange(of: textFieldState) { oldValue, newValue in
if !newValue {
if !title.isEmpty {
memo.title = title
memo.updatedAt = .now
} else {
title = memo.title
}
withPersistence(\.viewContext) { context in
try context.saveIfNeeded()
}
}
}
.transition(.move(edge: .top).combined(with: .blurReplace))
}
var historyControl: some View {
HStack {
Button {
history.historyPublisher.send(.undo)
} label: {
Image(systemName: "arrow.uturn.backward.circle")
.contentShape(.circle)
}
.hoverEffect(.lift)
.disabled(history.undoDisabled)
Button {
history.historyPublisher.send(.redo)
} label: {
Image(systemName: "arrow.uturn.forward.circle")
.contentShape(.circle)
}
.hoverEffect(.lift)
.disabled(history.redoDisabled)
}
.frame(width: size * 2, height: size)
.background(.regularMaterial)
.clipShape(.rect(cornerRadius: 8))
.disabled(textFieldState)
.transition(.move(edge: .top).combined(with: .blurReplace))
}
var gridModeControl: some View {
Menu {
ForEach(GridMode.all, id: \.self) { mode in
Button {
canvas.setGridMode(mode)
} label: {
Label {
Text(mode.title)
} icon: {
Image(systemName: mode.icon)
}
.font(.headline)
}
}
} label: {
Image(systemName: canvas.gridMode.icon)
.contentShape(.circle)
.frame(width: size, height: size)
.background(.regularMaterial)
.clipShape(.rect(cornerRadius: 8))
}
.hoverEffect(.lift)
.contentTransition(.symbolEffect(.replace))
.transition(.move(edge: .top).combined(with: .blurReplace))
}
func closeMemo() {
withAnimation {
canvas.state = .closing
}
withPersistenceSync(\.viewContext) { context in
try context.saveIfNeeded()
}
withPersistence(\.backgroundContext) { context in
try context.saveIfNeeded()
context.refreshAllObjects()
DispatchQueue.main.async {
withAnimation {
canvas.state = .closed
}
dismiss()
}
}
}
}