Compare commits
2 Commits
main
...
app/add-re
Author | SHA1 | Date | |
---|---|---|---|
cd8adb6f66 | |||
2f8e3a094d |
@ -42,6 +42,57 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"settings.button.add-repository.text" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Add repository"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings.column.active.text" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Active"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings.column.folder.text" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Folder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings.column.name.text" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings.item.active.text" : {
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"settings.tab-bar.repositories.text" : {
|
"settings.tab-bar.repositories.text" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
|
@ -15,24 +15,34 @@ final class Repository {
|
|||||||
// MARK: Properties
|
// MARK: Properties
|
||||||
|
|
||||||
@Attribute(.unique) var path: URL
|
@Attribute(.unique) var path: URL
|
||||||
|
|
||||||
var addedAt: Date
|
var addedAt: Date
|
||||||
var sortOrder: Int
|
var active: Bool
|
||||||
|
|
||||||
// MARK: Initialisers
|
// MARK: Initialisers
|
||||||
|
|
||||||
init(
|
init(
|
||||||
_ path: URL,
|
_ path: URL,
|
||||||
sortOrder: Int,
|
active: Bool = true,
|
||||||
addedAt: Date = .now
|
addedAt: Date = .now
|
||||||
) {
|
) {
|
||||||
self.path = path
|
self.path = path
|
||||||
self.addedAt = addedAt
|
self.addedAt = addedAt
|
||||||
self.sortOrder = sortOrder
|
self.active = active
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Computed
|
// MARK: Computed
|
||||||
|
|
||||||
@Transient var name: String { path.lastPathComponent }
|
@Transient var folder: String {
|
||||||
|
path.deletingLastPathComponent().relativePath
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transient var name: String {
|
||||||
|
path.lastPathComponent
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Identifiable
|
||||||
|
|
||||||
|
extension Repository: Identifiable {}
|
||||||
|
37
Piper/Sources/Logic/ViewModels/RepositoriesViewModel.swift
Normal file
37
Piper/Sources/Logic/ViewModels/RepositoriesViewModel.swift
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// RepositoriesViewModel.swift
|
||||||
|
// Piper ~ App
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 21/10/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Observation
|
||||||
|
import SwiftData
|
||||||
|
|
||||||
|
@Observable
|
||||||
|
final class RepositoriesViewModel {
|
||||||
|
|
||||||
|
// MARK: Properties
|
||||||
|
|
||||||
|
var fileImporterOpened: Bool = false
|
||||||
|
var rowsSelected: Set<Repository.ID> = []
|
||||||
|
|
||||||
|
// MARK: Functions
|
||||||
|
|
||||||
|
func addRepository(
|
||||||
|
_ result: Result<URL, any Error>,
|
||||||
|
into context: ModelContext
|
||||||
|
) {
|
||||||
|
do {
|
||||||
|
let url = try result.get()
|
||||||
|
let repository = Repository(url)
|
||||||
|
|
||||||
|
context.insert(repository)
|
||||||
|
} catch {
|
||||||
|
// TODO: Handle this error gracefully.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -18,18 +18,16 @@ extension Repository {
|
|||||||
let context = container.mainContext
|
let context = container.mainContext
|
||||||
|
|
||||||
context.insert(Repository(
|
context.insert(Repository(
|
||||||
URL(filePath: "/full/path/to/repository/name-0.git"),
|
URL(filePath: "/full/path/to/repository/name-0.git")
|
||||||
sortOrder: 0
|
|
||||||
))
|
))
|
||||||
|
|
||||||
context.insert(Repository(
|
context.insert(Repository(
|
||||||
URL(filePath: "/full/path/to/repository/name-1.git"),
|
URL(filePath: "/full/path/to/repository/name-1.git"),
|
||||||
sortOrder: 1
|
active: false
|
||||||
))
|
))
|
||||||
|
|
||||||
context.insert(Repository(
|
context.insert(Repository(
|
||||||
URL(filePath: "/full/path/to/repository/name-2.git"),
|
URL(filePath: "/full/path/to/repository/name-2.git")
|
||||||
sortOrder: 2
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,24 +62,15 @@ struct ItemLabelStyle: LabelStyle {
|
|||||||
|
|
||||||
#Preview("List Item component") {
|
#Preview("List Item component") {
|
||||||
List {
|
List {
|
||||||
ListItem(
|
ListItem(repository: .init(
|
||||||
repository: .init(
|
.init(filePath: "/full/path/to/repository/name.git")!
|
||||||
.init(filePath: "/full/path/to/repository/name.git")!,
|
))
|
||||||
sortOrder: 0
|
ListItem(repository: .init(
|
||||||
)
|
.init(filePath: "/full/path/to/repository/name.git")!
|
||||||
)
|
))
|
||||||
ListItem(
|
ListItem(repository: .init(
|
||||||
repository: .init(
|
.init(filePath: "/full/path/to/repository/name.git")!
|
||||||
.init(filePath: "/full/path/to/repository/name.git")!,
|
))
|
||||||
sortOrder: 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
ListItem(
|
|
||||||
repository: .init(
|
|
||||||
.init(filePath: "/full/path/to/repository/name.git")!,
|
|
||||||
sortOrder: 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
.frame(width: 400, height: 220)
|
.frame(width: 400, height: 220)
|
||||||
}
|
}
|
||||||
|
117
Piper/Sources/UI/Views/RepositoriesView.swift
Normal file
117
Piper/Sources/UI/Views/RepositoriesView.swift
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
//
|
||||||
|
// RepositoriesView.swift
|
||||||
|
// Piper ~ App
|
||||||
|
//
|
||||||
|
// Created by Javier Cicchelli on 14/10/2024.
|
||||||
|
// Copyright © 2024 Röck+Cöde. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftData
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct RepositoriesView: View {
|
||||||
|
|
||||||
|
// MARK: Properties
|
||||||
|
|
||||||
|
@Environment(\.modelContext) private var modelContext
|
||||||
|
|
||||||
|
@Query(sort: \Repository.addedAt)
|
||||||
|
private var repositories: [Repository]
|
||||||
|
|
||||||
|
@State private var viewModel: RepositoriesViewModel = .init()
|
||||||
|
|
||||||
|
// MARK: Body
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
HStack(
|
||||||
|
alignment: .top,
|
||||||
|
spacing: Layout.spacingHorizontal
|
||||||
|
) {
|
||||||
|
Table(
|
||||||
|
repositories,
|
||||||
|
selection: $viewModel.rowsSelected
|
||||||
|
) {
|
||||||
|
TableColumn("settings.column.active.text") { repository in
|
||||||
|
HStack {
|
||||||
|
Toggle("settings.item.active.text", isOn: .init {
|
||||||
|
repository.active
|
||||||
|
} set: {
|
||||||
|
repository.active = $0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TableColumn("settings.column.name.text") { repository in
|
||||||
|
Text(repository.name)
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
.foregroundStyle(.primary)
|
||||||
|
}
|
||||||
|
|
||||||
|
TableColumn("settings.column.folder.text") { repository in
|
||||||
|
Text(repository.folder)
|
||||||
|
.fontWeight(.regular)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack {
|
||||||
|
Button("settings.button.add-repository.text") {
|
||||||
|
viewModel.fileImporterOpened = true
|
||||||
|
}
|
||||||
|
.fileImporter(
|
||||||
|
isPresented: $viewModel.fileImporterOpened,
|
||||||
|
allowedContentTypes: [.pdf]
|
||||||
|
) {
|
||||||
|
viewModel.addRepository($0, into: modelContext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Layout
|
||||||
|
|
||||||
|
private extension RepositoriesView {
|
||||||
|
enum Layout {
|
||||||
|
static let spacingHorizontal = CGFloat(16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Previews
|
||||||
|
|
||||||
|
@available(macOS 15.0, *)
|
||||||
|
#Preview(
|
||||||
|
"Repositories view when no repositories found (macOS 15)",
|
||||||
|
traits: .emptyData
|
||||||
|
) {
|
||||||
|
RepositoriesView()
|
||||||
|
.scenePadding()
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS, obsoleted: 15)
|
||||||
|
#Preview("Repositories view when no repositories found (macOS 14)") {
|
||||||
|
MenuBarView()
|
||||||
|
.modelContainer(.preview)
|
||||||
|
.scenePadding()
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS 15.0, *)
|
||||||
|
#Preview(
|
||||||
|
"Repositories view when repositories found (macOS 15)",
|
||||||
|
traits: .sampleData
|
||||||
|
) {
|
||||||
|
RepositoriesView()
|
||||||
|
.scenePadding()
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(macOS, obsoleted: 15)
|
||||||
|
#Preview("Repositories view when repositories found (macOS 14)") {
|
||||||
|
let container = ModelContainer.preview
|
||||||
|
|
||||||
|
Repository.samples(in: container)
|
||||||
|
|
||||||
|
return RepositoriesView()
|
||||||
|
.modelContainer(container)
|
||||||
|
.scenePadding()
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user