Last active
February 8, 2025 03:16
-
-
Save jspence1234/c442df89110e077725e5217a6b176624 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// JacobsWorkApp.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on [Date] | |
// | |
import SwiftUI | |
import SwiftData | |
@main | |
struct JacobsWorkApp: App { | |
let modelContainer: ModelContainer | |
init() { | |
do { | |
// Provide model types as a variadic list, now including PullSheet and PullSheetItem | |
self.modelContainer = try ModelContainer( | |
for: | |
TodoItem.self, | |
StickyNote.self, | |
Note.self, | |
Part.self, | |
PullSheet.self, | |
PullSheetItem.self | |
) | |
} catch { | |
fatalError("Failed to initialize ModelContainer: \(error.localizedDescription)") | |
} | |
} | |
var body: some Scene { | |
WindowGroup { | |
ContentView() | |
.modelContainer(modelContainer) | |
.task { | |
// Run CSV importer if needed | |
let importer = PartImporter(container: modelContainer) | |
await importer.importCSVIfNeeded() | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Note.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
import SwiftData | |
@Model | |
final class Note: Identifiable { | |
var title: String | |
var content: String | |
var dateCreated: Date | |
init(title: String, content: String, dateCreated: Date = Date()) { | |
self.title = title | |
self.content = content | |
self.dateCreated = dateCreated | |
} | |
} | |
// | |
// NoteViewModel.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
import Combine | |
import Foundation | |
class NoteViewModel: ObservableObject { | |
@Published var notes: [Note] = [] | |
/// Adds a new note to the array. | |
func addNote(title: String, content: String) { | |
let newNote = Note(title: title, content: content) | |
notes.append(newNote) | |
} | |
/// Deletes notes at the given offsets (used by .onDelete). | |
func deleteNotes(at offsets: IndexSet) { | |
notes.remove(atOffsets: offsets) | |
} | |
/// Updates an existing note’s title/content if it still exists in the array. | |
func updateNote(note: Note, title: String, content: String) { | |
if let index = notes.firstIndex(where: { $0.id == note.id }) { | |
notes[index].title = title | |
notes[index].content = content | |
} | |
} | |
} | |
// | |
// Part.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
import SwiftData | |
@Model | |
final class Part: Identifiable { | |
var partNumber: String | |
var partDescription: String | |
var binLocation: String | |
init(partNumber: String, partDescription: String, binLocation: String) { | |
self.partNumber = partNumber | |
self.partDescription = partDescription | |
self.binLocation = binLocation | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
@Model | |
final class PullSheet: ObservableObject, Identifiable { | |
var id: UUID | |
var title: String | |
var items: [PullSheetItem] | |
init(title: String, items: [PullSheetItem] = []) { | |
self.id = UUID() | |
self.title = title | |
self.items = items | |
} | |
} | |
// | |
// PullSheetItem.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on [Date] | |
// | |
import SwiftUI | |
import SwiftData | |
@Model | |
final class PullSheetItem: Identifiable { | |
var id: UUID | |
var part: Part | |
var quantity: Int | |
init(part: Part, quantity: Int) { | |
self.id = UUID() | |
self.part = part | |
self.quantity = quantity | |
} | |
} | |
// | |
// StickyNote.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on [Date] | |
// | |
import SwiftUI | |
import SwiftData | |
@Model | |
final class StickyNote: Identifiable { | |
var id: UUID | |
var textContent: String? | |
var imageData: Data? | |
var dateCreated: Date | |
var isCompleted: Bool | |
init( | |
textContent: String? = nil, | |
imageData: Data? = nil, | |
dateCreated: Date = Date(), | |
isCompleted: Bool = false | |
) { | |
self.id = UUID() | |
self.textContent = textContent | |
self.imageData = imageData | |
self.dateCreated = dateCreated | |
self.isCompleted = isCompleted | |
} | |
} | |
// | |
// TodoItem.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on [Date] | |
// | |
import SwiftUI | |
import SwiftData | |
@Model | |
final class TodoItem: Identifiable { | |
var title: String | |
var isCompleted: Bool | |
var dueDate: Date? // Optional due date | |
var isRecurring: Bool // false: one-time, true: every day | |
init(title: String, isCompleted: Bool = false, dueDate: Date? = nil, isRecurring: Bool = false) { | |
self.title = title | |
self.isCompleted = isCompleted | |
self.dueDate = dueDate | |
self.isRecurring = isRecurring | |
} | |
} | |
// | |
// TodoViewModel.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on [Date] | |
// | |
import SwiftUI | |
class TodoViewModel: ObservableObject { | |
@Published var todos: [TodoItem] = [] | |
func addTodo(title: String, isRecurring: Bool = false) { | |
todos.append(TodoItem(title: title, isRecurring: isRecurring)) | |
} | |
func toggleTodoCompletion(todo: TodoItem) { | |
todo.isCompleted.toggle() | |
} | |
func updateTodo(todo: TodoItem, title: String, isRecurring: Bool) { | |
if let index = todos.firstIndex(where: { $0.id == todo.id }) { | |
todos[index].title = title | |
todos[index].isRecurring = isRecurring | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CloudSyncManager.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import Foundation | |
import CloudKit | |
class CloudSyncManager { | |
// Code to manage iCloud/CloudKit synchronization | |
} | |
// | |
// Helpers.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import Foundation | |
struct Helpers { | |
// General utility functions can be added here | |
} | |
import SwiftData | |
import Foundation | |
@MainActor | |
class PartImporter { | |
let container: ModelContainer | |
init(container: ModelContainer) { | |
self.container = container | |
} | |
func importCSVIfNeeded() async { | |
do { | |
let context = container.mainContext | |
let fetchDescriptor = FetchDescriptor<Part>(sortBy: []) | |
let existingParts = try context.fetch(fetchDescriptor) | |
if existingParts.isEmpty { | |
if let url = Bundle.main.url(forResource: "parts", withExtension: "csv") { | |
let data = try Data(contentsOf: url) | |
if let csvString = String(data: data, encoding: .utf8) { | |
// Split the CSV string by newlines to get each row | |
let lines = csvString.components(separatedBy: .newlines) | |
// Assume the first line is the header, so skip it. | |
try context.transaction { | |
for line in lines.dropFirst() where !line.isEmpty { | |
// Split each line by comma | |
let columns = line.components(separatedBy: ",") | |
// Make sure you have at least 3 columns: partNumber, partDescription, binLocation | |
if columns.count >= 3 { | |
let part = Part( | |
partNumber: columns[0], | |
partDescription: columns[1], | |
binLocation: columns[2] | |
) | |
context.insert(part) | |
} | |
} | |
} | |
} | |
} | |
} | |
} catch { | |
print("Error importing CSV: \(error.localizedDescription)") | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// AddFromPartsView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct AddFromPartsView: View { | |
@State private var searchText: String = "" | |
var body: some View { | |
VStack { | |
HStack { | |
Text("Add Item from Parts") | |
.font(.largeTitle) | |
Spacer() | |
Button("<") { } | |
} | |
.padding() | |
TextField("Search Parts", text: $searchText) | |
.padding() | |
.textFieldStyle(RoundedBorderTextFieldStyle()) | |
List { | |
// Sample parts list filtered by searchText | |
Text("12345 - Widget A: High quality widget, Bin: 3B") | |
Text("22345 - Numeric Sensor: Precision measurement, Bin: 1A") | |
Text("32345 - Dumbbell Set: Weighted equipment") | |
} | |
} | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct AddPullSheetItemView: View { | |
@ObservedObject var pullSheet: PullSheet | |
@Environment(\.modelContext) private var modelContext | |
@Environment(\.dismiss) private var dismiss | |
@State private var searchText: String = "" | |
@State private var selectedPart: Part? = nil | |
@State private var quantity: String = "" | |
@Query(sort: \Part.partNumber, animation: .default) private var parts: [Part] | |
private var filteredParts: [Part] { | |
if searchText.isEmpty { | |
return parts | |
} else { | |
let q = searchText.lowercased() | |
return parts.filter { | |
$0.partNumber.lowercased().contains(q) || | |
$0.partDescription.lowercased().contains(q) | |
} | |
} | |
} | |
var body: some View { | |
NavigationStack { | |
VStack { | |
if selectedPart == nil { | |
TextField("Search Parts", text: $searchText) | |
.textFieldStyle(RoundedBorderTextFieldStyle()) | |
.padding() | |
List(filteredParts, id: \.id) { part in | |
Button(action: { | |
selectedPart = part | |
}) { | |
VStack(alignment: .leading) { | |
Text(part.partNumber) | |
.font(.headline) | |
Text(part.partDescription) | |
.font(.subheadline) | |
} | |
} | |
} | |
} else { | |
Form { | |
Section(header: Text("Selected Part")) { | |
if let part = selectedPart { | |
Text(part.partNumber) | |
.font(.headline) | |
Text(part.partDescription) | |
.font(.subheadline) | |
} | |
} | |
Section(header: Text("Quantity")) { | |
TextField("Quantity", text: $quantity) | |
.keyboardType(.numberPad) | |
} | |
} | |
.navigationTitle("Add Item") | |
.toolbar { | |
ToolbarItem(placement: .navigationBarTrailing) { | |
Button("Save") { | |
guard let part = selectedPart, | |
let qty = Int(quantity), | |
qty > 0 else { return } | |
let newItem = PullSheetItem(part: part, quantity: qty) | |
pullSheet.items.append(newItem) | |
modelContext.insert(newItem) | |
dismiss() | |
} | |
} | |
ToolbarItem(placement: .navigationBarLeading) { | |
Button("Back") { | |
selectedPart = nil | |
quantity = "" | |
} | |
} | |
} | |
} | |
} | |
.navigationTitle(selectedPart == nil ? "Select Part" : "Add Item") | |
.toolbar { | |
ToolbarItem(placement: .navigationBarLeading) { | |
Button("Cancel") { | |
dismiss() | |
} | |
} | |
} | |
} | |
} | |
} | |
// | |
// AnalyticsView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct AnalyticsView: View { | |
var body: some View { | |
VStack { | |
Text("Analytics") | |
.font(.largeTitle) | |
// Placeholder charts and stats | |
Text("[Chart: Task Completion Rate Over Time]") | |
.padding() | |
Text("[Chart: Orders Placed Per Day]") | |
.padding() | |
Text("Summary Stats: Total Tasks, Completed Orders") | |
.padding() | |
HStack { | |
Button("Filter by Date") { } | |
Spacer() | |
Button("Export Report") { } | |
} | |
.padding() | |
} | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct ContentView: View { | |
@StateObject private var todoViewModel = TodoViewModel() | |
@StateObject private var noteViewModel = NoteViewModel() // For other notes if needed | |
var body: some View { | |
TabView { | |
NavigationStack { | |
DashboardView(todoViewModel: todoViewModel) | |
} | |
.tabItem { | |
Image(systemName: "house.fill") | |
Text("Dashboard") | |
} | |
NavigationStack { | |
TodoListView() // Your tasks view | |
.environmentObject(todoViewModel) | |
} | |
.tabItem { | |
Image(systemName: "checkmark.circle.fill") | |
Text("Tasks") | |
} | |
NavigationStack { | |
StickyNotesTabView() // NEW: Dedicated Sticky Notes tab | |
} | |
.tabItem { | |
Image(systemName: "square.and.pencil") | |
Text("Sticky Notes") | |
} | |
NavigationStack { | |
PartLookupView() // Parts catalog view | |
} | |
.tabItem { | |
Image(systemName: "magnifyingglass") | |
Text("Parts") | |
} | |
NavigationStack { | |
PullSheetListView() // PullSheets view | |
} | |
.tabItem { | |
Image(systemName: "doc.on.doc") | |
Text("PullSheets") | |
} | |
NavigationStack { | |
SettingsView() | |
} | |
.tabItem { | |
Image(systemName: "gearshape.fill") | |
Text("Settings") | |
} | |
} | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct DashboardView: View { | |
@ObservedObject var todoViewModel: TodoViewModel | |
@State private var newTaskTitle: String = "" | |
@State private var newTaskRecurring: Bool = false // false = one-time, true = every day | |
@State private var selectedTask: TodoItem? = nil | |
@State private var selectedStickyNote: StickyNote? = nil // new state for sticky note selection | |
@Query private var stickyNotes: [StickyNote] | |
@Environment(\.modelContext) private var modelContext | |
@State private var showNotepadSheet: Bool = false | |
var body: some View { | |
NavigationStack { | |
HStack(alignment: .top) { | |
// Left column: Sticky Notes Grid with onSelect closure | |
StickyNoteGridView(stickyNotes: stickyNotes, onSelect: { note in | |
selectedStickyNote = note | |
}) | |
.frame(maxWidth: .infinity) | |
// Right column: Task list with inline addition | |
VStack(alignment: .leading) { | |
HStack { | |
TextField("New Task", text: $newTaskTitle) | |
.textFieldStyle(RoundedBorderTextFieldStyle()) | |
Picker("", selection: $newTaskRecurring) { | |
Text("One-Time").tag(false) | |
Text("Every Day").tag(true) | |
} | |
.pickerStyle(SegmentedPickerStyle()) | |
Button(action: { | |
guard !newTaskTitle.isEmpty else { return } | |
todoViewModel.addTodo(title: newTaskTitle, isRecurring: newTaskRecurring) | |
newTaskTitle = "" | |
newTaskRecurring = false | |
}, label: { | |
Image(systemName: "plus.circle.fill") | |
.font(.title) | |
}) | |
} | |
.padding() | |
ScrollView { | |
LazyVStack(spacing: 10) { | |
ForEach(todoViewModel.todos) { task in | |
TodoCardView(task: task) | |
.onTapGesture { | |
selectedTask = task | |
} | |
} | |
} | |
.padding() | |
} | |
.sheet(item: $selectedTask) { task in | |
TodoDetailView(task: task, todoViewModel: todoViewModel) | |
} | |
} | |
.frame(maxWidth: .infinity) | |
} | |
.navigationTitle("Dashboard") | |
.toolbar { | |
ToolbarItem(placement: .navigationBarTrailing) { | |
Button(action: { | |
showNotepadSheet.toggle() | |
}) { | |
Image(systemName: "square.and.pencil") | |
} | |
} | |
} | |
.fullScreenCover(isPresented: $showNotepadSheet) { | |
FullScreenNotepadView() | |
} | |
// New fullScreenCover to present the sticky note detail when one is tapped | |
.fullScreenCover(item: $selectedStickyNote) { note in | |
StickyNoteDetailView(note: note) | |
} | |
} | |
} | |
} | |
// | |
// DrawingNoteView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
import PencilKit | |
struct DrawingNoteView: View { | |
@State private var canvasView = PKCanvasView() | |
@State private var tool: PKTool = PKInkingTool(.pen, color: .black, width: 3) | |
@Environment(\.dismiss) private var dismiss | |
var body: some View { | |
VStack { | |
// The Canvas | |
PencilCanvasView(canvasView: $canvasView, tool: $tool) | |
.background(Color(UIColor.secondarySystemBackground)) | |
.cornerRadius(10) | |
.padding() | |
// The Save Button | |
Button("Save") { | |
let drawingImage = captureDrawing() | |
if let filename = saveImageToDocuments(drawingImage) { | |
print("Saved drawing as \(filename)") | |
} | |
dismiss() // Pop back in the navigation stack | |
} | |
.padding() | |
} | |
.navigationTitle("Drawing Note") | |
} | |
/// Renders the PencilKit drawing into a UIImage | |
private func captureDrawing() -> UIImage { | |
let bounds = canvasView.bounds | |
return canvasView.drawing.image(from: bounds, scale: UIScreen.main.scale) | |
} | |
/// Saves the UIImage to the app’s Documents directory and returns the filename if successful | |
private func saveImageToDocuments(_ image: UIImage) -> String? { | |
guard let data = image.pngData() else { return nil } | |
let filename = "drawing_\(UUID().uuidString).png" | |
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! | |
let fileURL = documentsURL.appendingPathComponent(filename) | |
do { | |
try data.write(to: fileURL) | |
return filename | |
} catch { | |
print("Error saving image: \(error.localizedDescription)") | |
return nil | |
} | |
} | |
} | |
// | |
// EditRecurringTaskView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct EditRecurringTaskView: View { | |
var body: some View { | |
VStack { | |
HStack { | |
Button("< Back") { } | |
Spacer() | |
Text("Edit Recurring Task") | |
.font(.headline) | |
Spacer() | |
} | |
.padding() | |
Form { | |
TextField("Task Title", text: .constant("")) | |
TextField("Description", text: .constant("")) | |
Picker("Frequency", selection: .constant("Daily")) { | |
Text("Daily").tag("Daily") | |
Text("Weekly").tag("Weekly") | |
Text("Monthly").tag("Monthly") | |
} | |
DatePicker("Next Due Date", selection: .constant(Date())) | |
} | |
HStack { | |
Button("Save Changes") { } | |
Spacer() | |
Button("Cancel") { } | |
} | |
.padding() | |
} | |
} | |
} | |
import SwiftUI | |
import PencilKit | |
import SwiftData | |
struct FullScreenNotepadView: View { | |
@Environment(\.dismiss) private var dismiss | |
@Environment(\.modelContext) private var modelContext | |
@State private var canvasView = PKCanvasView() | |
@State private var textContent: String = "" | |
@State private var selectedColor: Color = .black | |
@State private var selectedWidth: CGFloat = 3 | |
@State private var tool: PKTool = PKInkingTool(.pen, color: .black, width: 3) | |
var body: some View { | |
NavigationStack { | |
VStack(spacing: 10) { | |
Text("Full Screen Notepad") | |
.font(.title2) | |
.fontWeight(.bold) | |
TextField("Enter note text...", text: $textContent) | |
.textFieldStyle(RoundedBorderTextFieldStyle()) | |
.padding() | |
PencilCanvasView(canvasView: $canvasView, tool: $tool) | |
.frame(height: 300) | |
.background(Color.white) | |
.cornerRadius(15) | |
.shadow(radius: 5) | |
toolSelectionControls() | |
HStack { | |
Button("Save") { | |
saveStickyNote() | |
dismiss() | |
} | |
.buttonStyle(.borderedProminent) | |
Button("Clear") { | |
clearCanvas() | |
} | |
.buttonStyle(.bordered) | |
.tint(.red) | |
Button("Close") { | |
dismiss() | |
} | |
.buttonStyle(.bordered) | |
} | |
.padding() | |
} | |
.navigationTitle("Notepad") | |
.toolbar { | |
ToolbarItem(placement: .navigationBarLeading) { | |
Button("Cancel") { | |
dismiss() | |
} | |
} | |
} | |
} | |
.ignoresSafeArea() // Ensures a full-screen experience | |
} | |
private func saveStickyNote() { | |
let imageData = canvasView.drawing.dataRepresentation() | |
let note = StickyNote( | |
textContent: textContent, | |
imageData: imageData, | |
dateCreated: Date(), | |
isCompleted: false | |
) | |
modelContext.insert(note) | |
} | |
private func clearCanvas() { | |
canvasView.drawing = PKDrawing() | |
} | |
private func toolSelectionControls() -> some View { | |
HStack { | |
ColorPicker("Color", selection: $selectedColor) | |
.onChange(of: selectedColor) { newValue in | |
tool = PKInkingTool(.pen, color: UIColor(newValue), width: selectedWidth) | |
} | |
Slider(value: $selectedWidth, in: 1...10, step: 1) | |
.onChange(of: selectedWidth) { newValue in | |
tool = PKInkingTool(.pen, color: UIColor(selectedColor), width: newValue) | |
} | |
} | |
.padding() | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct NewPullSheetView: View { | |
@Environment(\.dismiss) private var dismiss | |
@Environment(\.modelContext) private var modelContext | |
@State private var title: String = "" | |
var body: some View { | |
NavigationStack { | |
Form { | |
Section(header: Text("Pull Sheet Title")) { | |
TextField("Title", text: $title) | |
} | |
} | |
.navigationTitle("New Pull Sheet") | |
.toolbar { | |
ToolbarItem(placement: .navigationBarTrailing) { | |
Button("Save") { | |
guard !title.isEmpty else { return } | |
let newSheet = PullSheet(title: title) | |
modelContext.insert(newSheet) | |
dismiss() | |
} | |
} | |
ToolbarItem(placement: .navigationBarLeading) { | |
Button("Cancel") { | |
dismiss() | |
} | |
} | |
} | |
} | |
} | |
} | |
// | |
// NoteDetailView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct NoteDetailView: View { | |
var note: Note | |
@ObservedObject var noteViewModel: NoteViewModel | |
@State private var title: String = "" | |
@State private var content: String = "" | |
var body: some View { | |
Form { | |
Section(header: Text("Title")) { | |
TextField("Title", text: $title) | |
} | |
Section(header: Text("Content")) { | |
TextField("Content", text: $content) | |
} | |
} | |
.navigationTitle("Edit Note") | |
.onAppear { | |
title = note.title | |
content = note.content | |
} | |
.toolbar { | |
ToolbarItem(placement: .navigationBarTrailing) { | |
Button("Save") { | |
noteViewModel.updateNote(note: note, title: title, content: content) | |
} | |
} | |
} | |
} | |
} | |
struct NoteDetailView_Previews: PreviewProvider { | |
static var previews: some View { | |
let sampleNote = Note(title: "Sample Note", content: "Sample content") | |
NavigationView { | |
NoteDetailView(note: sampleNote, noteViewModel: NoteViewModel()) | |
} | |
.navigationViewStyle(StackNavigationViewStyle()) | |
} | |
} | |
// | |
// NotepadView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct NotepadView: View { | |
var body: some View { | |
VStack { | |
HStack { | |
Text("Notepad") | |
.font(.largeTitle) | |
Spacer() | |
// Save, Undo, Redo icons could be added here | |
} | |
.padding() | |
TextEditor(text: .constant("Write your note here...")) | |
.padding() | |
HStack { | |
Button("Pen") { } | |
Button("Highlighter") { } | |
Button("Eraser") { } | |
Button("Color") { } | |
} | |
.padding() | |
} | |
} | |
} | |
// | |
// NotesView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
import SwiftData | |
struct NotesView: View { | |
@Query private var stickyNotes: [StickyNote] | |
@ObservedObject var noteViewModel: NoteViewModel | |
var body: some View { | |
List { | |
ForEach(stickyNotes) { note in | |
HStack { | |
if let imageData = note.imageData, let uiImage = UIImage(data: imageData) { | |
Image(uiImage: uiImage) | |
.resizable() | |
.scaledToFit() | |
.frame(width: 60, height: 60) | |
.cornerRadius(8) | |
} | |
VStack(alignment: .leading) { | |
if let text = note.textContent { | |
Text(text) | |
.font(.headline) | |
} | |
Text(note.dateCreated, style: .date) | |
.font(.caption) | |
.foregroundColor(.gray) | |
} | |
} | |
} | |
} | |
.navigationTitle("Sticky Notes") | |
} | |
} | |
// | |
// OrdersView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct OrdersView: View { | |
var body: some View { | |
NavigationView { | |
VStack { | |
Text("Orders") | |
.font(.largeTitle) | |
.padding() | |
List { | |
ForEach(0..<5) { index in | |
HStack { | |
Image(systemName: "bag") | |
.foregroundColor(.blue) | |
VStack(alignment: .leading) { | |
Text("Order #\(index + 1)") | |
.font(.headline) | |
Text("Order details here") | |
.font(.subheadline) | |
.foregroundColor(.secondary) | |
} | |
} | |
.padding(.vertical, 4) | |
} | |
} | |
} | |
.navigationTitle("Orders") | |
} | |
.navigationViewStyle(StackNavigationViewStyle()) | |
} | |
} | |
struct OrdersView_Previews: PreviewProvider { | |
static var previews: some View { | |
OrdersView() | |
} | |
} | |
import SwiftUI | |
struct PartDetailView: View { | |
let part: Part | |
var body: some View { | |
Form { | |
Section(header: Text("Part Info")) { | |
Text("Part Number: \(part.partNumber)") | |
Text("Description: \(part.partDescription)") | |
Text("Bin: \(part.binLocation)") | |
} | |
} | |
.navigationTitle("Part Detail") | |
.navigationBarTitleDisplayMode(.inline) | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct PartLookupView: View { | |
@State private var searchText: String = "" | |
@Query(sort: \Part.partNumber, animation: .default) private var parts: [Part] | |
private var filteredParts: [Part] { | |
if searchText.isEmpty { | |
return parts | |
} else { | |
let q = searchText.lowercased() | |
return parts.filter { | |
$0.partNumber.lowercased().contains(q) || | |
$0.partDescription.lowercased().contains(q) | |
} | |
} | |
} | |
var body: some View { | |
List(filteredParts, id: \.id) { part in | |
NavigationLink(destination: PartDetailView(part: part)) { | |
VStack(alignment: .leading) { | |
Text(part.partNumber) | |
.font(.headline) | |
Text(part.partDescription) | |
.font(.subheadline) | |
Text("Bin: \(part.binLocation)") | |
.font(.caption) | |
.foregroundColor(.secondary) | |
} | |
} | |
} | |
.navigationTitle("Parts Catalog") | |
.searchable(text: $searchText, placement: .navigationBarDrawer(displayMode: .always)) | |
} | |
} | |
import SwiftUI | |
import PencilKit | |
struct PencilCanvasView: UIViewRepresentable { | |
@Binding var canvasView: PKCanvasView | |
@Binding var tool: PKTool | |
func makeUIView(context: Context) -> PKCanvasView { | |
canvasView.drawingPolicy = .anyInput | |
canvasView.tool = tool | |
return canvasView | |
} | |
func updateUIView(_ uiView: PKCanvasView, context: Context) { | |
uiView.tool = tool | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct PullSheetDetailView: View { | |
@ObservedObject var pullSheet: PullSheet | |
@Environment(\.modelContext) private var modelContext | |
@State private var showAddItemSheet = false | |
var body: some View { | |
Form { | |
Section(header: Text("Pull Sheet Items")) { | |
ForEach(pullSheet.items) { item in | |
HStack { | |
VStack(alignment: .leading) { | |
Text(item.part.partNumber) | |
.font(.headline) | |
Text(item.part.partDescription) | |
.font(.subheadline) | |
} | |
Spacer() | |
Text("Qty: \(item.quantity)") | |
} | |
.swipeActions { | |
Button(role: .destructive) { | |
modelContext.delete(item) | |
} label: { | |
Label("Delete", systemImage: "trash") | |
} | |
} | |
} | |
} | |
} | |
.navigationTitle(pullSheet.title) | |
.toolbar { | |
ToolbarItem(placement: .navigationBarTrailing) { | |
Button(action: { showAddItemSheet.toggle() }) { | |
Image(systemName: "plus") | |
} | |
} | |
} | |
.sheet(isPresented: $showAddItemSheet) { | |
AddPullSheetItemView(pullSheet: pullSheet) | |
} | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct PullSheetListView: View { | |
@Query private var pullSheets: [PullSheet] | |
@Environment(\.modelContext) private var modelContext | |
@State private var showNewPullSheetSheet = false | |
var body: some View { | |
NavigationStack { | |
List { | |
ForEach(pullSheets) { pullSheet in | |
NavigationLink(destination: PullSheetDetailView(pullSheet: pullSheet)) { | |
Text(pullSheet.title) | |
} | |
.swipeActions { | |
Button(role: .destructive) { | |
modelContext.delete(pullSheet) | |
} label: { | |
Label("Delete", systemImage: "trash") | |
} | |
} | |
} | |
} | |
.navigationTitle("Pull Sheets") | |
.toolbar { | |
ToolbarItem(placement: .navigationBarTrailing) { | |
Button(action: { showNewPullSheetSheet.toggle() }) { | |
Image(systemName: "plus") | |
} | |
} | |
} | |
.sheet(isPresented: $showNewPullSheetSheet) { | |
NewPullSheetView() | |
} | |
} | |
} | |
} | |
// | |
// PullSheetsView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct PullSheetsView: View { | |
var body: some View { | |
VStack { | |
Text("Pull Sheets") | |
.font(.largeTitle) | |
.padding() | |
Text("Pull Sheets functionality goes here.") | |
.padding() | |
} | |
.navigationTitle("Pull Sheets") | |
} | |
} | |
struct PullSheetsView_Previews: PreviewProvider { | |
static var previews: some View { | |
NavigationView { | |
PullSheetsView() | |
} | |
.navigationViewStyle(StackNavigationViewStyle()) | |
} | |
} | |
// | |
// QuickNoteView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct QuickNoteView: View { | |
var body: some View { | |
VStack { | |
Text("Quick Note") | |
.font(.headline) | |
TextEditor(text: .constant("Start writing here...")) | |
.frame(height: 100) | |
.padding() | |
} | |
} | |
} | |
// | |
// SettingsView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct SettingsView: View { | |
@State private var sortOption: String = "Date" | |
@State private var theme: String = "Light" | |
var body: some View { | |
Form { | |
Section(header: Text("Sorting")) { | |
Picker("Sort By", selection: $sortOption) { | |
Text("Date").tag("Date") | |
Text("Title").tag("Title") | |
Text("Status").tag("Status") | |
} | |
.pickerStyle(SegmentedPickerStyle()) | |
} | |
Section(header: Text("Appearance")) { | |
Picker("Theme", selection: $theme) { | |
Text("Light").tag("Light") | |
Text("Dark").tag("Dark") | |
} | |
.pickerStyle(SegmentedPickerStyle()) | |
} | |
} | |
.navigationTitle("Settings") | |
} | |
} | |
struct SettingsView_Previews: PreviewProvider { | |
static var previews: some View { | |
NavigationView { | |
SettingsView() | |
} | |
.navigationViewStyle(StackNavigationViewStyle()) | |
} | |
} | |
// | |
// ShareButton.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct ShareButton: View { | |
let image: UIImage | |
@State private var isShowingShareSheet = false | |
var body: some View { | |
Button("Share") { | |
isShowingShareSheet = true | |
} | |
.sheet(isPresented: $isShowingShareSheet) { | |
ShareSheet(activityItems: [image]) | |
} | |
} | |
} | |
/// A UIViewControllerRepresentable that presents the iOS Share Sheet | |
struct ShareSheet: UIViewControllerRepresentable { | |
let activityItems: [Any] | |
func makeUIViewController(context: Context) -> UIActivityViewController { | |
UIActivityViewController(activityItems: activityItems, applicationActivities: nil) | |
} | |
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) { } | |
} | |
import SwiftUI | |
import SwiftData | |
struct StickyNoteDetailView: View { | |
@Environment(\.modelContext) private var modelContext | |
let note: StickyNote | |
var body: some View { | |
ScrollView { | |
VStack(spacing: 16) { | |
if let imageData = note.imageData, let uiImage = UIImage(data: imageData) { | |
Image(uiImage: uiImage) | |
.resizable() | |
.scaledToFit() | |
.cornerRadius(10) | |
.padding() | |
} | |
if let text = note.textContent { | |
Text(text) | |
.font(.title3) | |
.multilineTextAlignment(.leading) | |
.padding(.horizontal) | |
} | |
Text(note.dateCreated, style: .date) | |
.font(.footnote) | |
.foregroundColor(.secondary) | |
// Optionally, include controls to mark complete or delete | |
Toggle("Mark Completed", isOn: bindingForIsCompleted) | |
.padding(.horizontal) | |
Button(role: .destructive) { | |
modelContext.delete(note) | |
} label: { | |
Text("Delete Sticky Note") | |
} | |
.padding() | |
} | |
} | |
.navigationTitle("Note Detail") | |
.navigationBarTitleDisplayMode(.inline) | |
} | |
private var bindingForIsCompleted: Binding<Bool> { | |
Binding( | |
get: { note.isCompleted }, | |
set: { note.isCompleted = $0 } | |
) | |
} | |
} | |
// | |
// StickyNoteGalleryView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
import SwiftData | |
struct StickyNoteGalleryView: View { | |
@Query private var stickyNotes: [StickyNote] | |
var body: some View { | |
List { | |
ForEach(stickyNotes) { note in | |
NavigationLink(destination: StickyNoteDetailView(note: note)) { | |
HStack { | |
if let data = note.imageData, | |
let uiImage = UIImage(data: data) { | |
Image(uiImage: uiImage) | |
.resizable() | |
.scaledToFit() | |
.frame(width: 60, height: 60) | |
.cornerRadius(8) | |
} | |
VStack(alignment: .leading) { | |
if let text = note.textContent { | |
Text(text) | |
.font(.headline) | |
.lineLimit(1) | |
} | |
Text(note.dateCreated, style: .date) | |
.font(.caption) | |
.foregroundColor(.secondary) | |
if note.isCompleted { | |
Text("Completed") | |
.font(.caption2) | |
.foregroundColor(.green) | |
} | |
} | |
Spacer() | |
} | |
} | |
} | |
} | |
.navigationTitle("Sticky Notes") | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct StickyNoteGridView: View { | |
let stickyNotes: [StickyNote] | |
var onSelect: (StickyNote) -> Void // Called when a note is tapped | |
@Environment(\.modelContext) private var modelContext | |
let columns = [ | |
GridItem(.flexible(), spacing: 16), | |
GridItem(.flexible(), spacing: 16) | |
] | |
var body: some View { | |
ScrollView { | |
LazyVGrid(columns: columns, spacing: 16) { | |
ForEach(stickyNotes) { note in | |
StickyNoteCell(note: note) | |
.onTapGesture { | |
onSelect(note) | |
} | |
.background(Color.white) | |
.cornerRadius(10) | |
.shadow(radius: 3) | |
.swipeActions { | |
Button(role: .destructive) { | |
modelContext.delete(note) | |
} label: { | |
Label("Delete", systemImage: "trash") | |
} | |
} | |
} | |
} | |
.padding() | |
} | |
} | |
} | |
struct StickyNoteCell: View { | |
let note: StickyNote | |
var body: some View { | |
VStack { | |
if let imageData = note.imageData, let uiImage = UIImage(data: imageData) { | |
Image(uiImage: uiImage) | |
.resizable() | |
.scaledToFill() | |
.frame(height: 120) | |
.clipped() | |
} else { | |
Rectangle() | |
.fill(Color.gray.opacity(0.3)) | |
.frame(height: 120) | |
} | |
if let text = note.textContent { | |
Text(text) | |
.font(.headline) | |
.lineLimit(2) | |
.padding([.leading, .trailing, .bottom], 8) | |
} | |
} | |
} | |
} | |
import SwiftUI | |
import SwiftData | |
struct StickyNotesTabView: View { | |
@Query private var stickyNotes: [StickyNote] | |
@Environment(\.modelContext) private var modelContext | |
@State private var showNotepadSheet: Bool = false | |
@State private var selectedStickyNote: StickyNote? = nil | |
var body: some View { | |
NavigationStack { | |
ZStack(alignment: .bottomTrailing) { | |
// Pass in a closure to handle selection | |
StickyNoteGridView(stickyNotes: stickyNotes, onSelect: { note in | |
selectedStickyNote = note | |
}) | |
// Floating button to add a sticky note | |
Button(action: { | |
showNotepadSheet.toggle() | |
}) { | |
Image(systemName: "plus.circle.fill") | |
.resizable() | |
.frame(width: 60, height: 60) | |
.foregroundColor(.blue) | |
.shadow(radius: 5) | |
.padding() | |
} | |
} | |
.navigationTitle("Sticky Notes") | |
// Full-screen cover for adding a new sticky note | |
.fullScreenCover(isPresented: $showNotepadSheet) { | |
FullScreenNotepadView() | |
} | |
// Full-screen cover for viewing a sticky note detail | |
.fullScreenCover(item: $selectedStickyNote) { note in | |
StickyNoteDetailView(note: note) | |
} | |
} | |
} | |
} | |
// | |
// StickyNoteView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
import PencilKit | |
import SwiftData | |
struct StickyNoteView: View { | |
@Environment(\.dismiss) private var dismiss | |
@Environment(\.modelContext) private var modelContext | |
@State private var canvasView = PKCanvasView() | |
@State private var textContent: String = "" | |
@State private var selectedColor: Color = .black | |
@State private var selectedWidth: CGFloat = 3 | |
@State private var tool: PKTool = PKInkingTool(.pen, color: .black, width: 3) | |
var body: some View { | |
VStack(spacing: 10) { | |
Text("New Sticky Note") | |
.font(.title2) | |
.fontWeight(.bold) | |
TextField("Enter note text...", text: $textContent) | |
.textFieldStyle(RoundedBorderTextFieldStyle()) | |
.padding() | |
PencilCanvasView(canvasView: $canvasView, tool: $tool) | |
.frame(height: 300) | |
.background(Color.white) | |
.cornerRadius(15) | |
.shadow(radius: 5) | |
toolSelectionControls() | |
HStack { | |
Button("Save") { | |
saveStickyNote() | |
dismiss() | |
} | |
.buttonStyle(.borderedProminent) | |
Button("Clear") { | |
clearCanvas() | |
} | |
.buttonStyle(.bordered) | |
.tint(.red) | |
Button("Close") { | |
dismiss() | |
} | |
.buttonStyle(.bordered) | |
} | |
.padding() | |
} | |
.padding() | |
.background(Color.white) | |
} | |
private func saveStickyNote() { | |
let imageData = canvasView.drawing.dataRepresentation() | |
let note = StickyNote( | |
textContent: textContent, | |
imageData: imageData, | |
dateCreated: Date(), | |
isCompleted: false | |
) | |
modelContext.insert(note) | |
} | |
private func clearCanvas() { | |
canvasView.drawing = PKDrawing() | |
} | |
private func toolSelectionControls() -> some View { | |
HStack { | |
// Tool selection controls (e.g., color picker and width slider) | |
ColorPicker("Color", selection: $selectedColor) | |
.onChange(of: selectedColor) { newValue in | |
tool = PKInkingTool(.pen, color: UIColor(newValue), width: selectedWidth) | |
} | |
Slider(value: $selectedWidth, in: 1...10, step: 1) | |
.onChange(of: selectedWidth) { newValue in | |
tool = PKInkingTool(.pen, color: UIColor(selectedColor), width: newValue) | |
} | |
} | |
.padding() | |
} | |
} | |
// | |
// TodoCardView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct TodoCardView: View { | |
let task: TodoItem | |
var body: some View { | |
HStack { | |
VStack(alignment: .leading, spacing: 8) { | |
Text(task.title) | |
.font(.headline) | |
Text(task.isRecurring ? "Every Day" : "One-Time") | |
.font(.subheadline) | |
.foregroundColor(.secondary) | |
} | |
Spacer() | |
Image(systemName: task.isCompleted ? "checkmark.circle.fill" : "circle") | |
.foregroundColor(task.isCompleted ? .green : .gray) | |
} | |
.padding() | |
.background(Color(UIColor.secondarySystemBackground)) | |
.cornerRadius(10) | |
} | |
} | |
import SwiftUI | |
struct TodoDetailView: View { | |
@State var task: TodoItem | |
@ObservedObject var todoViewModel: TodoViewModel | |
@Environment(\.dismiss) private var dismiss | |
var body: some View { | |
NavigationStack { | |
Form { | |
Section(header: Text("Task Title")) { | |
TextField("Title", text: $task.title) | |
} | |
Section(header: Text("Task Type")) { | |
Picker("Task Type", selection: $task.isRecurring) { | |
Text("One-Time").tag(false) | |
Text("Every Day").tag(true) | |
} | |
.pickerStyle(SegmentedPickerStyle()) | |
} | |
Section { | |
Toggle("Completed", isOn: $task.isCompleted) | |
} | |
} | |
.navigationTitle("Edit Task") | |
.toolbar { | |
ToolbarItem(placement: .navigationBarTrailing) { | |
Button("Save") { | |
todoViewModel.updateTodo(todo: task, title: task.title, isRecurring: task.isRecurring) | |
dismiss() | |
} | |
} | |
} | |
} | |
} | |
} | |
// | |
// TodoListView.swift | |
// JacobsWorkApp | |
// | |
// Created by Jacob Spence on 2/7/25. | |
// | |
import SwiftUI | |
struct TodoListView: View { | |
@EnvironmentObject var todoViewModel: TodoViewModel | |
@State private var newTodoTitle: String = "" | |
var body: some View { | |
VStack { | |
List { | |
ForEach(todoViewModel.todos) { todo in | |
HStack { | |
Button(action: { | |
todoViewModel.toggleTodoCompletion(todo: todo) | |
}) { | |
Image(systemName: todo.isCompleted ? "checkmark.circle.fill" : "circle") | |
} | |
Text(todo.title) | |
.strikethrough(todo.isCompleted, color: .gray) | |
} | |
} | |
} | |
HStack { | |
TextField("New Todo", text: $newTodoTitle) | |
.textFieldStyle(RoundedBorderTextFieldStyle()) | |
Button("Add") { | |
guard !newTodoTitle.isEmpty else { return } | |
todoViewModel.addTodo(title: newTodoTitle) | |
newTodoTitle = "" | |
} | |
} | |
.padding() | |
} | |
.navigationTitle("Todos") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment