[App] Open settings (#5)
This PR contains the work done to open the *Settings* view and also, implemented the rendering of its tab items. Reviewed-on: #5 Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Co-committed-by: Javier Cicchelli <javier@rock-n-code.com>
This commit is contained in:
parent
3d78c599d1
commit
58ac646e25
@ -431,7 +431,7 @@
|
|||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
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;
|
DEVELOPMENT_TEAM = 7FMNM89WKG;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@ -463,7 +463,7 @@
|
|||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
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;
|
DEVELOPMENT_TEAM = 7FMNM89WKG;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "en",
|
"sourceLanguage" : "en",
|
||||||
"strings" : {
|
"strings" : {
|
||||||
"Add Item" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"Item at %@" : {
|
|
||||||
|
|
||||||
},
|
|
||||||
"menu-bar.item.empty.button.text" : {
|
"menu-bar.item.empty.button.text" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
@ -48,8 +42,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Select an item" : {
|
"settings.tab-bar.repositories.text" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Repositories"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version" : "1.0"
|
"version" : "1.0"
|
||||||
|
@ -35,6 +35,10 @@ struct PiperApp: App {
|
|||||||
Image(systemName: "circle.fill")
|
Image(systemName: "circle.fill")
|
||||||
}
|
}
|
||||||
.menuBarExtraStyle(.window)
|
.menuBarExtraStyle(.window)
|
||||||
|
|
||||||
|
Settings {
|
||||||
|
SettingsView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,5 @@ extension Schema {
|
|||||||
static let entities = Schema([
|
static let entities = Schema([
|
||||||
Repository.self
|
Repository.self
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
@ -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 () {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
20
Piper/Sources/Logic/ViewModels/SettingsViewModel.swift
Normal file
20
Piper/Sources/Logic/ViewModels/SettingsViewModel.swift
Normal file
@ -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
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// ModelContainer+Constants.swift
|
// ModelContainer+Constants.swift
|
||||||
// Piper
|
// Piper ~ App
|
||||||
//
|
//
|
||||||
// Created by Javier Cicchelli on 06/10/2024.
|
// Created by Javier Cicchelli on 06/10/2024.
|
||||||
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
@ -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())
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
//
|
//
|
||||||
// Repository+Samples.swift
|
// Repository+Samples.swift
|
||||||
// Piper
|
// Piper ~ App
|
||||||
//
|
//
|
||||||
// Created by Javier Cicchelli on 06/10/2024.
|
// Created by Javier Cicchelli on 06/10/2024.
|
||||||
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
27
Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift
Normal file
27
Piper/Sources/Previews/Modifiers/EmptyDataModifier.swift
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
31
Piper/Sources/Previews/Modifiers/SampleDataModifier.swift
Normal file
31
Piper/Sources/Previews/Modifiers/SampleDataModifier.swift
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
Piper/Sources/UI/Enumerations/SettingsItem.swift
Normal file
35
Piper/Sources/UI/Enumerations/SettingsItem.swift
Normal file
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
Piper/Sources/UI/Extensions/SettingsItem+Properties.swift
Normal file
27
Piper/Sources/UI/Extensions/SettingsItem+Properties.swift
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
@ -13,11 +13,11 @@ struct MenuBarView: View {
|
|||||||
|
|
||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
|
@Environment(\.openSettings) private var openSettings
|
||||||
|
|
||||||
@Query(sort: \Repository.sortOrder)
|
@Query(sort: \Repository.sortOrder)
|
||||||
private var repositories: [Repository]
|
private var repositories: [Repository]
|
||||||
|
|
||||||
@State private var viewMode = MenuBarViewModel()
|
|
||||||
|
|
||||||
// MARK: Body
|
// MARK: Body
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
@ -28,7 +28,7 @@ struct MenuBarView: View {
|
|||||||
title: "menu-bar.item.empty.title.text",
|
title: "menu-bar.item.empty.title.text",
|
||||||
button: "menu-bar.item.empty.button.text"
|
button: "menu-bar.item.empty.button.text"
|
||||||
) {
|
) {
|
||||||
// ...
|
openSettings()
|
||||||
}
|
}
|
||||||
.frame(height: Layout.heightEmpty)
|
.frame(height: Layout.heightEmpty)
|
||||||
} else {
|
} else {
|
||||||
@ -66,11 +66,29 @@ private extension MenuBarView {
|
|||||||
|
|
||||||
// MARK: - Previews
|
// 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") {
|
#Preview("Menu Bar view when no repositories found") {
|
||||||
MenuBarView()
|
MenuBarView()
|
||||||
.modelContainer(.preview)
|
.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") {
|
#Preview("Menu Bar view when some repositories found") {
|
||||||
let container = ModelContainer.preview
|
let container = ModelContainer.preview
|
||||||
|
|
||||||
|
74
Piper/Sources/UI/Views/SettingsView.swift
Normal file
74
Piper/Sources/UI/Views/SettingsView.swift
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//
|
||||||
|
// 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: Properties
|
||||||
|
|
||||||
|
@State private var viewModel: SettingsViewModel = .init()
|
||||||
|
|
||||||
|
// MARK: Body
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
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 {
|
||||||
|
SettingsView()
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user