Skip to content

Commit

Permalink
Merge pull request #336 from aapis/feature/1.18/term-management
Browse files Browse the repository at this point in the history
New feature: Term management
  • Loading branch information
aapis authored Nov 12, 2024
2 parents 3940fca + 7b0f75f commit e986eff
Show file tree
Hide file tree
Showing 14 changed files with 534 additions and 95 deletions.
19 changes: 17 additions & 2 deletions KWCore/Sources/Helpers/SearchHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public final class SearchHelper {
public var recordBucket: [LogRecord] = []
public var companyBucket: [Company] = []
public var definitionsBucket: [TaxonomyTermDefinitions] = []
public var termBucket: [TaxonomyTerm] = []
public var peopleBucket: [Person] = []
public var fields: [String] = []

Expand Down Expand Up @@ -44,6 +45,10 @@ public final class SearchHelper {
self.definitionsBucket = bucket
}

public init(bucket: [TaxonomyTerm]) {
self.termBucket = bucket
}

public init(bucket: [Person]) {
self.peopleBucket = bucket
}
Expand Down Expand Up @@ -91,6 +96,7 @@ public final class SearchHelper {
matches(searchText, fields: [$0.name!]) && $0.hidden == allowHidden
}
}

/// Find matching entities of type TaxonomyTermDefinitions
/// - Parameter searchText: Binding(String)
/// - Returns: [NSManagedObject]
Expand All @@ -99,7 +105,7 @@ public final class SearchHelper {
matches(searchText, fields: [$0.definition!, $0.term!.name!])
}
}

/// Find matching entities of type Person
/// - Parameter searchText: Binding(String)
/// - Returns: [NSManagedObject]
Expand All @@ -108,7 +114,16 @@ public final class SearchHelper {
matches(searchText, fields: [$0.name!])
}
}


/// Find matching entities of type TaxonomyTerm
/// - Parameter searchText: Binding(String)
/// - Returns: [NSManagedObject]
public func findInTerms(_ searchText: Binding<String>) -> [TaxonomyTerm] {
return termBucket.filter {
matches(searchText, fields: [$0.name!])
}
}

private func matches(_ searchText: Binding<String>, fields: [String]) -> Bool {
do {
let caseInsensitiveTerm = try Regex(searchText.wrappedValue).ignoresCase()
Expand Down
6 changes: 6 additions & 0 deletions KWCore/Sources/Query/CoreDataTaxonomyTermDefinitions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,12 @@ open class CoreDataTaxonomyTermDefinitions {
)
}

/// Count all taxonomy terms
/// - Returns: Int
public func countAll() -> Int {
return self.count(NSPredicate(format: "alive == true"))
}

/// Create a new TaxonomyTermDefinitions
/// - Parameters:
/// - alive: Bool
Expand Down
64 changes: 64 additions & 0 deletions KWCore/Sources/Query/CoreDataTaxonomyTerms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,70 @@ public class CoreDataTaxonomyTerms {
return self.count(NSPredicate(format: "alive == true"))
}

/// Create a new TaxonomyTerm
/// - Parameters:
/// - alive: Bool
/// - created: Optional(Date)
/// - lastUpdate: Optional(Date)
/// - name: String
/// - definitions: Optional([TaxonomyTermDefinitions])
/// - saveByDefault: Bool
/// - Returns: Void
public func createAndReturn(alive: Bool, created: Date? = nil, lastUpdate: Date? = nil, name: String, definitions: [TaxonomyTermDefinitions]? = nil, saveByDefault: Bool = true) -> TaxonomyTerm {
return self.make(
alive: alive,
created: created,
lastUpdate: lastUpdate,
name: name,
definitions: definitions,
saveByDefault: saveByDefault
)
}

/// Create a new TaxonomyTerm
/// - Parameters:
/// - alive: Bool
/// - created: Optional(Date)
/// - lastUpdate: Optional(Date)
/// - name: String
/// - definitions: Optional([TaxonomyTermDefinitions])
/// - saveByDefault: Bool
/// - Returns: Void
public func create(alive: Bool, created: Date? = nil, lastUpdate: Date? = nil, name: String, definitions: [TaxonomyTermDefinitions]? = nil, saveByDefault: Bool = true) -> Void {
let _ = self.make(
alive: alive,
created: created,
lastUpdate: lastUpdate,
name: name,
definitions: definitions,
saveByDefault: saveByDefault
)
}

/// Create a new TaxonomyTerm
/// - Parameters:
/// - alive: Bool
/// - created: Optional(Date)
/// - lastUpdate: Optional(Date)
/// - name: String
/// - definitions: Optional([TaxonomyTermDefinitions])
/// - saveByDefault: Bool
/// - Returns: TaxonomyTerm
private func make(alive: Bool, created: Date? = nil, lastUpdate: Date? = nil, name: String, definitions: [TaxonomyTermDefinitions]? = nil, saveByDefault: Bool = true) -> TaxonomyTerm {
let term = TaxonomyTerm(context: self.moc!)
term.alive = alive
term.created = created ?? Date()
term.lastUpdate = lastUpdate ?? Date()
term.name = name
term.definitions = NSSet(array: definitions ?? [])

if saveByDefault {
PersistenceController.shared.save()
}

return term
}

/// Query function, finds and filters notes
/// - Parameter predicate: A predicate to modify the results
/// - Returns: Array<NoteVersion>
Expand Down
126 changes: 126 additions & 0 deletions KWCore/Sources/UI/WidgetLibrary/WidgetLibrary.Blocks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ extension WidgetLibrary.UI {
struct Definition: View {
@EnvironmentObject public var state: Navigation
public var definition: TaxonomyTermDefinitions
public var icon: String? = nil
@State private var isHighlighted: Bool = false

var body: some View {
Expand All @@ -27,6 +28,9 @@ extension WidgetLibrary.UI {
HStack(alignment: .top, spacing: 10) {
Text(self.definition.definition ?? "Error: Missing definition")
Spacer()
if let icon = self.icon {
Image(systemName: icon)
}
}
.padding(8)
.background(self.isHighlighted ? (self.definition.job?.backgroundColor ?? Theme.rowColour).opacity(1) : (self.definition.job?.backgroundColor ?? Theme.rowColour).opacity(0.8)) // @TODO: refactor, this sucks
Expand Down Expand Up @@ -113,9 +117,131 @@ extension WidgetLibrary.UI {
.onChange(of: self.item) { self.actionOnAppear() }
}
}

// MARK: Term
struct Term: View {
@EnvironmentObject public var state: Navigation
public let term: TaxonomyTerm
@State private var highlighted: Bool = false

var body: some View {
Button {
self.actionOnTap()
} label: {
VStack(spacing: 0) {
ZStack(alignment: .topLeading) {
Color.white
.shadow(color: .black.opacity(1), radius: 3)
.opacity(highlighted ? 0.2 : 0.1)
VStack(alignment: .leading, spacing: 10) {
Text(self.term.name ?? "_TERM_NAME")
.font(.title3)
.fontWeight(.bold)
.padding([.leading, .trailing, .top])
if let defs = self.term.definitions {
if defs.count == 1 {
Text("\(defs.count) Definition")
.foregroundStyle(.white.opacity(0.55))
.padding([.leading, .trailing, .bottom])
} else {
Text("\(defs.count) Definitions")
.foregroundStyle(.white.opacity(0.55))
.padding([.leading, .trailing, .bottom])
}
}
Spacer()
UI.ResourcePath(
company: self.state.session.job?.project?.company,
project: self.state.session.job?.project,
job: self.state.session.job
)
}
}
}
}
.frame(height: 150)
.clipShape(.rect(cornerRadius: 5))
.useDefaultHover({ inside in highlighted = inside})
.buttonStyle(.plain)
}
}

// MARK: DefinitionAlternative
struct DefinitionAlternative: View {
@EnvironmentObject public var state: Navigation
public let definition: TaxonomyTermDefinitions
@State private var highlighted: Bool = false

var body: some View {
Button {
self.actionOnTap()
} label: {
VStack(spacing: 0) {
ZStack(alignment: .topLeading) {
Color.white
.shadow(color: .black.opacity(1), radius: 3)
.opacity(highlighted ? 0.2 : 0.1)
VStack(alignment: .leading, spacing: 10) {
Text(self.definition.term?.name ?? "_TERM_NAME")
.font(.title3)
.fontWeight(.bold)
.padding([.leading, .trailing, .top])
Text(self.definitionBody())
.foregroundStyle(.white.opacity(0.55))
.padding([.leading, .trailing, .bottom])
Spacer()
UI.ResourcePath(
company: self.state.session.job?.project?.company,
project: self.state.session.job?.project,
job: self.state.session.job
)
}
}
}
}
.frame(height: 150)
.clipShape(.rect(cornerRadius: 5))
.useDefaultHover({ inside in highlighted = inside})
.buttonStyle(.plain)
}
}
}
}

extension WidgetLibrary.UI.Blocks.Term {
/// Fires when a term block is clicked/tapped
/// - Returns: Void
private func actionOnTap() -> Void {
self.state.to(.termDetail)
self.state.session.term = self.term
}
}

extension WidgetLibrary.UI.Blocks.DefinitionAlternative {
/// Trucate term answer
/// - Returns: String
private func definitionBody() -> String {
if let body = self.definition.definition {
if body.count > 100 {
let i = body.index(body.startIndex, offsetBy: 100)
let description = String(body[...i]).trimmingCharacters(in: .whitespacesAndNewlines)

return description + "..."
}
}

return "No preview available"
}

/// Fires when a term block is clicked/tapped
/// - Returns: Void
private func actionOnTap() -> Void {
self.state.session.definition = self.definition
self.state.to(.definitionDetail)
}
}


extension WidgetLibrary.UI.Blocks.GenericBlock {
/// Onload handler. Sets view state
/// - Returns: Void
Expand Down
43 changes: 42 additions & 1 deletion KWCore/Sources/UI/WidgetLibrary/WidgetLibrary.UI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ extension WidgetLibrary {
var body: some View {
VStack(spacing: 0) {
ListLinkTitle(text: "Overview")
.padding(.bottom, 5)
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .center) {
ForEach(self.statistics, id: \.id) { type in type }
Expand Down Expand Up @@ -2029,6 +2030,23 @@ extension WidgetLibrary.UI.DaysWhereMentioned {
}
}

let plans = CoreDataPlan(moc: self.state.moc).forToday(self.state.session.date)
if !plans.isEmpty {
for plan in plans {
if let date = plan.created {
let components = calendar.dateComponents([.day], from: date)
if !self.days.contains(where: {
let co = calendar.dateComponents([.day], from: $0.date)
return co.day == components.day
}) {
self.days.append(
Day(type: .plans, date: date)
)
}
}
}
}

self.days = self.days.sorted(by: {$0.date > $1.date})
}
}
Expand Down Expand Up @@ -2497,6 +2515,28 @@ extension WidgetLibrary.UI.GenericTimelineActivity {
}
}

// @TODO: This doesn't work just yet
// let plans = CoreDataPlan(moc: self.state.moc).forToday(self.historicalDate)
// let calendar = Calendar.autoupdatingCurrent
// if !plans.isEmpty {
// for plan in plans {
// if let date = plan.created {
// let components = calendar.dateComponents([.day], from: date)
// if !self.activities.contains(where: {
// let co = calendar.dateComponents([.day], from: $0.historicalDate)
// return co.day == components.day
// }) {
// self.activities.append(
// UI.GenericTimelineActivity(
// historicalDate: date,
// view: AnyView(plan.rowView)
// )
// )
// }
// }
// }
// }

self.activities = self.activities.sorted(by: {self.tableSortOrder == 0 ? $0.historicalDate > $1.historicalDate : $0.historicalDate < $1.historicalDate})

// Find the current page of resources by offset
Expand Down Expand Up @@ -2798,7 +2838,7 @@ extension WidgetLibrary.UI.EntityStatistics {
/// Onload handler. Sets view state
/// - Returns: Void
private func actionOnAppear() -> Void {
let types = PageConfiguration.EntityType.allCases.filter({ ![.BruceWillis, .definitions].contains($0) })
let types = PageConfiguration.EntityType.allCases.filter({ ![.BruceWillis, .plans].contains($0) })

for type in types {
self.statistics.append(
Expand Down Expand Up @@ -2833,6 +2873,7 @@ extension WidgetLibrary.UI.EntityStatistics.Statistic {
case .companies: self.count = CoreDataCompanies(moc: self.state.moc).countAll()
case .projects: self.count = CoreDataProjects(moc: self.state.moc).countAll()
case .terms: self.count = CoreDataTaxonomyTerms(moc: self.state.moc).countAll()
case .definitions: self.count = CoreDataTaxonomyTermDefinitions(moc: self.state.moc).countAll()
default: self.count = 0
}
}
Expand Down
Loading

0 comments on commit e986eff

Please sign in to comment.