From e72888361a34f0892f137dd515c555907c19156f Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 19:32:32 +0200 Subject: [PATCH 01/10] Removed the ContentView view and the Item model boilerplates from the app target. --- Piper/Sources/Logic/Models/Item.swift | 19 -------- Piper/Sources/UI/Views/ContentView.swift | 60 ------------------------ 2 files changed, 79 deletions(-) delete mode 100644 Piper/Sources/Logic/Models/Item.swift delete mode 100644 Piper/Sources/UI/Views/ContentView.swift diff --git a/Piper/Sources/Logic/Models/Item.swift b/Piper/Sources/Logic/Models/Item.swift deleted file mode 100644 index f2fca05..0000000 --- a/Piper/Sources/Logic/Models/Item.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// Item.swift -// Piper ~ App -// -// Created by Javier Cicchelli on 04/10/2024. -// Copyright © 2024 Röck+Cöde. All rights reserved. -// - -import Foundation -import SwiftData - -@Model -final class Item { - var timestamp: Date - - init(timestamp: Date) { - self.timestamp = timestamp - } -} diff --git a/Piper/Sources/UI/Views/ContentView.swift b/Piper/Sources/UI/Views/ContentView.swift deleted file mode 100644 index 64a5ef2..0000000 --- a/Piper/Sources/UI/Views/ContentView.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// ContentView.swift -// Piper ~ App -// -// Created by Javier Cicchelli on 04/10/2024. -// Copyright © 2024 Röck+Cöde. All rights reserved. -// - -import SwiftUI -import SwiftData - -struct ContentView: View { - @Environment(\.modelContext) private var modelContext - @Query private var items: [Item] - - var body: some View { - NavigationSplitView { - List { - ForEach(items) { item in - NavigationLink { - Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))") - } label: { - Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) - } - } - .onDelete(perform: deleteItems) - } - .navigationSplitViewColumnWidth(min: 180, ideal: 200) - .toolbar { - ToolbarItem { - Button(action: addItem) { - Label("Add Item", systemImage: "plus") - } - } - } - } detail: { - Text("Select an item") - } - } - - private func addItem() { - withAnimation { - let newItem = Item(timestamp: Date()) - modelContext.insert(newItem) - } - } - - private func deleteItems(offsets: IndexSet) { - withAnimation { - for index in offsets { - modelContext.delete(items[index]) - } - } - } -} - -#Preview { - ContentView() - .modelContainer(for: Item.self, inMemory: true) -} -- 2.47.1 From 7889394fab1988d29e37a97eab9470bfe6265889 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 20:26:59 +0200 Subject: [PATCH 02/10] Implemented the EmptyDataModifier and the SampleDataModifier modifiers in the app target and also, added them as properties for the PreviewTrait+Properties extension. --- Piper.xcodeproj/project.pbxproj | 4 +-- .../Extensions/ModelContainer+Constants.swift | 2 +- .../Extensions/PreviewTrait+Properties.swift | 19 ++++++++++++ .../Extensions/Repository+Samples.swift | 2 +- .../Modifiers/EmptyDataModifier.swift | 27 ++++++++++++++++ .../Modifiers/SampleDataModifier.swift | 31 +++++++++++++++++++ 6 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 Piper/Sources/Previews/Extensions/PreviewTrait+Properties.swift create mode 100644 Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift create mode 100644 Piper/Sources/Previews/Modifiers/SampleDataModifier.swift diff --git a/Piper.xcodeproj/project.pbxproj b/Piper.xcodeproj/project.pbxproj index e9c7c3f..cbb4c68 100644 --- a/Piper.xcodeproj/project.pbxproj +++ b/Piper.xcodeproj/project.pbxproj @@ -431,7 +431,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "Piper/Sources/Previews/Extensions/Repository+Samples.swift Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift Piper/Resources/Catalogs/Previews.xcassets"; + DEVELOPMENT_ASSET_PATHS = "Piper/Sources/Previews/Extensions/PreviewTrait+Properties.swift Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift Piper/Resources/Catalogs/Previews.xcassets Piper/Sources/Previews/Extensions/Repository+Samples.swift Piper/Sources/Previews/Modifiers/SampleDataModifier.swift Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift"; DEVELOPMENT_TEAM = 7FMNM89WKG; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; @@ -463,7 +463,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_ASSET_PATHS = "Piper/Sources/Previews/Extensions/Repository+Samples.swift Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift Piper/Resources/Catalogs/Previews.xcassets"; + DEVELOPMENT_ASSET_PATHS = "Piper/Sources/Previews/Extensions/PreviewTrait+Properties.swift Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift Piper/Resources/Catalogs/Previews.xcassets Piper/Sources/Previews/Extensions/Repository+Samples.swift Piper/Sources/Previews/Modifiers/SampleDataModifier.swift Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift"; DEVELOPMENT_TEAM = 7FMNM89WKG; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; diff --git a/Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift b/Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift index 21d51a5..6ae202c 100644 --- a/Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift +++ b/Piper/Sources/Previews/Extensions/ModelContainer+Constants.swift @@ -1,6 +1,6 @@ // // ModelContainer+Constants.swift -// Piper +// Piper ~ App // // Created by Javier Cicchelli on 06/10/2024. // Copyright © 2024 Röck+Cöde. All rights reserved. diff --git a/Piper/Sources/Previews/Extensions/PreviewTrait+Properties.swift b/Piper/Sources/Previews/Extensions/PreviewTrait+Properties.swift new file mode 100644 index 0000000..d41ef68 --- /dev/null +++ b/Piper/Sources/Previews/Extensions/PreviewTrait+Properties.swift @@ -0,0 +1,19 @@ +// +// PreviewTrait+Properties.swift +// Piper +// +// Created by Javier Cicchelli on 13/10/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import SwiftUI + +@available(macOS 15.0, *) +extension PreviewTrait where T == Preview.ViewTraits { + + // MARK: Properties + + @MainActor static var emptyData: PreviewTrait = .modifier(EmptyDataModifier()) + @MainActor static var sampleData: PreviewTrait = .modifier(SampleDataModifier()) + +} diff --git a/Piper/Sources/Previews/Extensions/Repository+Samples.swift b/Piper/Sources/Previews/Extensions/Repository+Samples.swift index 9264b5b..f275d5b 100644 --- a/Piper/Sources/Previews/Extensions/Repository+Samples.swift +++ b/Piper/Sources/Previews/Extensions/Repository+Samples.swift @@ -1,6 +1,6 @@ // // Repository+Samples.swift -// Piper +// Piper ~ App // // Created by Javier Cicchelli on 06/10/2024. // Copyright © 2024 Röck+Cöde. All rights reserved. diff --git a/Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift b/Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift new file mode 100644 index 0000000..4ad5c1a --- /dev/null +++ b/Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift @@ -0,0 +1,27 @@ +// +// EmptyDataModifier.swift +// Piper ~ App +// +// Created by Javier Cicchelli on 13/10/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import SwiftData +import SwiftUI + +struct EmptyDataModifier: PreviewModifier { + + // MARK: Functions + + static func makeSharedContext() async throws -> ModelContainer { + ModelContainer.preview + } + + func body( + content: Content, + context: ModelContainer + ) -> some View { + content.modelContainer(context) + } + +} diff --git a/Piper/Sources/Previews/Modifiers/SampleDataModifier.swift b/Piper/Sources/Previews/Modifiers/SampleDataModifier.swift new file mode 100644 index 0000000..118b0a9 --- /dev/null +++ b/Piper/Sources/Previews/Modifiers/SampleDataModifier.swift @@ -0,0 +1,31 @@ +// +// SampleDataModifier.swift +// Piper ~ App +// +// Created by Javier Cicchelli on 13/10/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import SwiftData +import SwiftUI + +struct SampleDataModifier: PreviewModifier { + + // MARK: Functions + + static func makeSharedContext() async throws -> ModelContainer { + let container = ModelContainer.preview + + Repository.samples(in: container) + + return container + } + + func body( + content: Content, + context: ModelContainer + ) -> some View { + content.modelContainer(context) + } + +} -- 2.47.1 From 99b2d88f67839e5aa29df8e53c6b9ca699db862e Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 20:27:49 +0200 Subject: [PATCH 03/10] Implemented exclusive macOS 15 previews for the MenuBarView view in the app target. --- Piper/Sources/UI/Views/MenuBarView.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Piper/Sources/UI/Views/MenuBarView.swift b/Piper/Sources/UI/Views/MenuBarView.swift index 9040121..ab361c6 100644 --- a/Piper/Sources/UI/Views/MenuBarView.swift +++ b/Piper/Sources/UI/Views/MenuBarView.swift @@ -66,11 +66,29 @@ private extension MenuBarView { // MARK: - Previews +@available(macOS 15.0, *) +#Preview( + "Menu Bar view when no repositories found", + traits: .emptyData +) { + MenuBarView() +} + +@available(macOS, obsoleted: 15) #Preview("Menu Bar view when no repositories found") { MenuBarView() .modelContainer(.preview) } +@available(macOS 15.0, *) +#Preview( + "Menu Bar view when some repositories found", + traits: .sampleData +) { + MenuBarView() +} + +@available(macOS, obsoleted: 15) #Preview("Menu Bar view when some repositories found") { let container = ModelContainer.preview -- 2.47.1 From 009f616d3e24929aa42cb9e519e5268260278155 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 20:28:33 +0200 Subject: [PATCH 04/10] Removed (at least, temporarily!) the MenuBarViewModel view model from the app target. --- .../Logic/ViewModels/MenuBarViewModel.swift | 20 ------------------- Piper/Sources/UI/Views/MenuBarView.swift | 4 +--- 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 Piper/Sources/Logic/ViewModels/MenuBarViewModel.swift diff --git a/Piper/Sources/Logic/ViewModels/MenuBarViewModel.swift b/Piper/Sources/Logic/ViewModels/MenuBarViewModel.swift deleted file mode 100644 index cb04301..0000000 --- a/Piper/Sources/Logic/ViewModels/MenuBarViewModel.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// MenuBarViewModel.swift -// Piper ~ App -// -// Created by Javier Cicchelli on 06/10/2024. -// Copyright © 2024 Röck+Cöde. All rights reserved. -// - -import Observation - -@Observable -final class MenuBarViewModel { - - // MARK: Initialisers - - init () { - - } - -} diff --git a/Piper/Sources/UI/Views/MenuBarView.swift b/Piper/Sources/UI/Views/MenuBarView.swift index ab361c6..29cde10 100644 --- a/Piper/Sources/UI/Views/MenuBarView.swift +++ b/Piper/Sources/UI/Views/MenuBarView.swift @@ -15,9 +15,7 @@ struct MenuBarView: View { @Query(sort: \Repository.sortOrder) private var repositories: [Repository] - - @State private var viewMode = MenuBarViewModel() - + // MARK: Body var body: some View { -- 2.47.1 From e5858c93bb85f5573f6a28654dd4d78a04f3d16d Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 20:29:42 +0200 Subject: [PATCH 05/10] Added the "openSettings" environment property to the MenuBarView view in the app target. --- Piper/Sources/UI/Views/MenuBarView.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Piper/Sources/UI/Views/MenuBarView.swift b/Piper/Sources/UI/Views/MenuBarView.swift index 29cde10..f0d89d1 100644 --- a/Piper/Sources/UI/Views/MenuBarView.swift +++ b/Piper/Sources/UI/Views/MenuBarView.swift @@ -13,6 +13,8 @@ struct MenuBarView: View { // MARK: Properties + @Environment(\.openSettings) private var openSettings + @Query(sort: \Repository.sortOrder) private var repositories: [Repository] @@ -26,7 +28,7 @@ struct MenuBarView: View { title: "menu-bar.item.empty.title.text", button: "menu-bar.item.empty.button.text" ) { - // ... + openSettings() } .frame(height: Layout.heightEmpty) } else { -- 2.47.1 From 90e2fb11d24429cb06df8c8b4323d79b72c20e67 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 20:44:11 +0200 Subject: [PATCH 06/10] Created the SettingsView view in the app target. --- .../Logic/Extensions/Schema+Constants.swift | 1 - Piper/Sources/UI/Views/SettingsView.swift | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 Piper/Sources/UI/Views/SettingsView.swift diff --git a/Piper/Sources/Logic/Extensions/Schema+Constants.swift b/Piper/Sources/Logic/Extensions/Schema+Constants.swift index 934a1c5..4022270 100644 --- a/Piper/Sources/Logic/Extensions/Schema+Constants.swift +++ b/Piper/Sources/Logic/Extensions/Schema+Constants.swift @@ -15,6 +15,5 @@ extension Schema { static let entities = Schema([ Repository.self ]) - } diff --git a/Piper/Sources/UI/Views/SettingsView.swift b/Piper/Sources/UI/Views/SettingsView.swift new file mode 100644 index 0000000..9580508 --- /dev/null +++ b/Piper/Sources/UI/Views/SettingsView.swift @@ -0,0 +1,26 @@ +// +// SettingsView.swift +// Piper ~ App +// +// Created by Javier Cicchelli on 13/10/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import SwiftUI + +struct SettingsView: View { + + // MARK: Body + + var body: some View { + Text("Hello, World!") + .padding() + } + +} + +// MARK: - Previews + +#Preview { + SettingsView() +} -- 2.47.1 From 0d790267430946a1cba1d6e9d0faeb9c7045f5ed Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 20:45:02 +0200 Subject: [PATCH 07/10] Integrated the SettingsView view into the Settings screen inside the body of the PiperApp app in the app target. --- Piper/Sources/App/PiperApp.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Piper/Sources/App/PiperApp.swift b/Piper/Sources/App/PiperApp.swift index b8975a9..50d81e5 100644 --- a/Piper/Sources/App/PiperApp.swift +++ b/Piper/Sources/App/PiperApp.swift @@ -35,6 +35,10 @@ struct PiperApp: App { Image(systemName: "circle.fill") } .menuBarExtraStyle(.window) + + Settings { + SettingsView() + } } } -- 2.47.1 From da37cf60e6a8c6d0a53ac40243ab2e16a3080be1 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 23:57:28 +0200 Subject: [PATCH 08/10] Implemented the SettingsItem enumeration in the app target. --- .../Resources/Catalogs/Localizable.xcstrings | 17 ++++----- .../UI/Enumerations/SettingsItem.swift | 35 +++++++++++++++++++ .../Extensions/SettingsItem+Properties.swift | 27 ++++++++++++++ 3 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 Piper/Sources/UI/Enumerations/SettingsItem.swift create mode 100644 Piper/Sources/UI/Extensions/SettingsItem+Properties.swift diff --git a/Piper/Resources/Catalogs/Localizable.xcstrings b/Piper/Resources/Catalogs/Localizable.xcstrings index f26d581..ab81321 100644 --- a/Piper/Resources/Catalogs/Localizable.xcstrings +++ b/Piper/Resources/Catalogs/Localizable.xcstrings @@ -1,12 +1,6 @@ { "sourceLanguage" : "en", "strings" : { - "Add Item" : { - - }, - "Item at %@" : { - - }, "menu-bar.item.empty.button.text" : { "localizations" : { "en" : { @@ -48,8 +42,15 @@ } } }, - "Select an item" : { - + "settings.tab-bar.repositories.text" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Repositories" + } + } + } } }, "version" : "1.0" diff --git a/Piper/Sources/UI/Enumerations/SettingsItem.swift b/Piper/Sources/UI/Enumerations/SettingsItem.swift new file mode 100644 index 0000000..71092fd --- /dev/null +++ b/Piper/Sources/UI/Enumerations/SettingsItem.swift @@ -0,0 +1,35 @@ +// +// SettingsItem.swift +// Piper ~ App +// +// Created by Javier Cicchelli on 13/10/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +enum SettingsItem: Int, Hashable { + case repositories = 0 +} + +// MARK: - CaseIterable + +extension SettingsItem: CaseIterable { + + // MARK: Computed + + var allCases: [SettingsItem] { + [.repositories] + } + +} + +// MARK: - Identifiable + +extension SettingsItem: Identifiable { + + // MARK: Computed + + var id: Int { + rawValue + } + +} diff --git a/Piper/Sources/UI/Extensions/SettingsItem+Properties.swift b/Piper/Sources/UI/Extensions/SettingsItem+Properties.swift new file mode 100644 index 0000000..80ec6b1 --- /dev/null +++ b/Piper/Sources/UI/Extensions/SettingsItem+Properties.swift @@ -0,0 +1,27 @@ +// +// SettingsItem+Properties.swift +// Piper ~ App +// +// Created by Javier Cicchelli on 13/10/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import SwiftUI + +extension SettingsItem { + + // MARK: Computed + + var icon: String { + switch self { + case .repositories: "folder" + } + } + + var title: LocalizedStringKey { + switch self { + case .repositories: "settings.tab-bar.repositories.text" + } + } + +} -- 2.47.1 From 863f681078fc834f4c6ee7b4bd1d55fb46055431 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Sun, 13 Oct 2024 23:59:16 +0200 Subject: [PATCH 09/10] Implemented the "tabSelected" and "tabs" properties for the SettingsViewModel view model in the app target. --- .../Logic/ViewModels/SettingsViewModel.swift | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Piper/Sources/Logic/ViewModels/SettingsViewModel.swift diff --git a/Piper/Sources/Logic/ViewModels/SettingsViewModel.swift b/Piper/Sources/Logic/ViewModels/SettingsViewModel.swift new file mode 100644 index 0000000..609b857 --- /dev/null +++ b/Piper/Sources/Logic/ViewModels/SettingsViewModel.swift @@ -0,0 +1,20 @@ +// +// SettingsViewModel.swift +// Piper ~ App +// +// Created by Javier Cicchelli on 13/10/2024. +// Copyright © 2024 Röck+Cöde. All rights reserved. +// + +import Observation + +@Observable +final class SettingsViewModel { + + // MARK: Properties + + var tabSelected: SettingsItem = .repositories + + let tabs: [SettingsItem] = SettingsItem.allCases + +} -- 2.47.1 From 2a888ba469857ae6fdbcfc8ca2905c75a1ce80a8 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Mon, 14 Oct 2024 00:04:57 +0200 Subject: [PATCH 10/10] Implemented the basic layout for the SettingsView view in the app target. --- Piper/Sources/UI/Views/SettingsView.swift | 52 ++++++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/Piper/Sources/UI/Views/SettingsView.swift b/Piper/Sources/UI/Views/SettingsView.swift index 9580508..b960b87 100644 --- a/Piper/Sources/UI/Views/SettingsView.swift +++ b/Piper/Sources/UI/Views/SettingsView.swift @@ -10,15 +10,63 @@ import SwiftUI struct SettingsView: View { + // MARK: Properties + + @State private var viewModel: SettingsViewModel = .init() + // MARK: Body var body: some View { - Text("Hello, World!") - .padding() + Group { + if #available(macOS 15.0, *) { + TabView(selection: $viewModel.tabSelected) { + ForEach(viewModel.tabs) { tabItem in + Tab( + tabItem.title, + systemImage: tabItem.icon, + value: tabItem + ) { + switch tabItem { + case .repositories: + Text(tabItem.title) + } + } + } + } + } else { + TabView(selection: $viewModel.tabSelected) { + ForEach(viewModel.tabs) { tabItem in + Group { + switch tabItem { + case .repositories: + Text(tabItem.title) + } + } + .tabItem { + Text(tabItem.title) + } + .tag(tabItem) + } + } + } + } + .scenePadding() + .frame( + width: Layout.sizeView.width, + height: Layout.sizeView.height + ) } } +// MARK: - Layout + +private extension SettingsView { + enum Layout { + static let sizeView = CGSize(width: 350, height: 250) + } +} + // MARK: - Previews #Preview { -- 2.47.1