Group tasks feature #3
@@ -1,6 +1,50 @@
|
|||||||
{
|
{
|
||||||
"sourceLanguage" : "en",
|
"sourceLanguage" : "en",
|
||||||
"strings" : {
|
"strings" : {
|
||||||
|
"enumeration.todo-group.title.completed" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Completed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enumeration.todo-group.title.overdue" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Overdue"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enumeration.todo-group.title.today" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Today"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enumeration.todo-group.title.upcoming" : {
|
||||||
|
"extractionState" : "manual",
|
||||||
|
"localizations" : {
|
||||||
|
"en" : {
|
||||||
|
"stringUnit" : {
|
||||||
|
"state" : "translated",
|
||||||
|
"value" : "Upcoming"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"view.new-task.navigation.title" : {
|
"view.new-task.navigation.title" : {
|
||||||
"extractionState" : "manual",
|
"extractionState" : "manual",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
/// Categorizes todo tasks into groups based on their due dates and completion status.
|
||||||
|
///
|
||||||
|
/// This enumeration provides a semantic grouping mechanism for organizing and filtering todo tasks throughout the application.
|
||||||
|
/// Each case represents a distinct category that helps users manage their tasks based on temporal relevance and completion state.
|
||||||
|
enum TodoGroup {
|
||||||
|
/// Tasks that have been marked as done, regardless of due date.
|
||||||
|
case completed
|
||||||
|
/// Tasks with due dates in the past that remain incomplete.
|
||||||
|
case overdue
|
||||||
|
/// Tasks due on the current day that are not yet completed.
|
||||||
|
case today
|
||||||
|
/// Tasks due in the future that are not yet completed.
|
||||||
|
case upcoming
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Computed
|
||||||
|
|
||||||
|
extension TodoGroup {
|
||||||
|
|
||||||
|
/// The color associated with the task group.
|
||||||
|
var color: Color {
|
||||||
|
switch self {
|
||||||
|
case .completed: .gray
|
||||||
|
case .overdue: .red
|
||||||
|
case .today: .blue
|
||||||
|
case .upcoming: .green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The system icon name for the task group.
|
||||||
|
var iconName: String {
|
||||||
|
switch self {
|
||||||
|
case .completed: "checkmark.circle.fill"
|
||||||
|
case .overdue: "calendar.badge.exclamationmark"
|
||||||
|
case .today: "calendar.badge.clock"
|
||||||
|
case .upcoming: "calendar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The display title for the task group.
|
||||||
|
var title: LocalizedStringKey {
|
||||||
|
switch self {
|
||||||
|
case .completed: "enumeration.todo-group.title.completed"
|
||||||
|
case .overdue: "enumeration.todo-group.title.overdue"
|
||||||
|
case .today: "enumeration.todo-group.title.today"
|
||||||
|
case .upcoming: "enumeration.todo-group.title.upcoming"
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - CaseIterable
|
||||||
|
|
||||||
|
extension TodoGroup: CaseIterable {
|
||||||
|
|
||||||
|
static var allCases: [TodoGroup] { [.today, .upcoming, .overdue, .completed] }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Identifiable
|
||||||
|
|
||||||
|
extension TodoGroup: Identifiable {
|
||||||
|
|
||||||
|
var id: Self { self }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
import Testing
|
||||||
|
|
||||||
|
@testable import Todos
|
||||||
|
|
||||||
|
@Suite("TodoGroup enumeration tests")
|
||||||
|
struct TodoGroupTests {
|
||||||
|
|
||||||
|
// MARK: Computed tests
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
"group color match expected values",
|
||||||
|
arguments: zip(
|
||||||
|
TodoGroup.allCases,
|
||||||
|
[Color.blue, .green, .red, .gray]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
func color(
|
||||||
|
for group: TodoGroup,
|
||||||
|
expects expectation: Color
|
||||||
|
) {
|
||||||
|
// GIVEN
|
||||||
|
// WHEN
|
||||||
|
let color = group.color
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
#expect(color == expectation)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
"group icon names match expected values",
|
||||||
|
arguments: zip(
|
||||||
|
TodoGroup.allCases,
|
||||||
|
["calendar.badge.clock", "calendar", "calendar.badge.exclamationmark", "checkmark.circle.fill"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
func iconName(
|
||||||
|
for group: TodoGroup,
|
||||||
|
expects expectation: String
|
||||||
|
) {
|
||||||
|
// GIVEN
|
||||||
|
// WHEN
|
||||||
|
let iconName = group.iconName
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
#expect(iconName == expectation)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(
|
||||||
|
"group titles match expected values",
|
||||||
|
arguments: zip(
|
||||||
|
TodoGroup.allCases,
|
||||||
|
["today", "upcoming", "overdue", "completed"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
func title(
|
||||||
|
for group: TodoGroup,
|
||||||
|
expects expectation: String
|
||||||
|
) {
|
||||||
|
// GIVEN
|
||||||
|
let key = "enumeration.todo-group.title." + expectation
|
||||||
|
|
||||||
|
// WHEN
|
||||||
|
let title = group.title
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
#expect(title == .init(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Case Iteration Tests
|
||||||
|
|
||||||
|
@Test("all cases contains all cases, in correct order")
|
||||||
|
func allCases() {
|
||||||
|
// GIVEN
|
||||||
|
// WHEN
|
||||||
|
let allCases = TodoGroup.allCases
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
#expect(allCases.count == 4)
|
||||||
|
#expect(allCases[0] == .today)
|
||||||
|
#expect(allCases[1] == .upcoming)
|
||||||
|
#expect(allCases[2] == .overdue)
|
||||||
|
#expect(allCases[3] == .completed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Identifiable Tests
|
||||||
|
|
||||||
|
@Test("id returns an identity of a case", arguments: TodoGroup.allCases)
|
||||||
|
func id(for group: TodoGroup) {
|
||||||
|
// GIVEN
|
||||||
|
// WHEN
|
||||||
|
let id = group.id
|
||||||
|
|
||||||
|
// THEN
|
||||||
|
#expect(id == group)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import Testing
|
|||||||
|
|
||||||
@testable import Todos
|
@testable import Todos
|
||||||
|
|
||||||
@Suite("ContentView.ViewModel Tests")
|
@Suite("ContentView view model tests")
|
||||||
struct ContentViewModelTests {
|
struct ContentViewModelTests {
|
||||||
|
|
||||||
// MARK: Initialization Tests
|
// MARK: Initialization Tests
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import Testing
|
|||||||
|
|
||||||
@testable import Todos
|
@testable import Todos
|
||||||
|
|
||||||
@Suite("NewTaskView ViewModel Tests")
|
@Suite("NewTaskView view model tests")
|
||||||
struct NewTaskViewModelTests {
|
struct NewTaskViewModelTests {
|
||||||
|
|
||||||
// MARK: Initialization tests
|
// MARK: Initialization tests
|
||||||
|
|||||||
Reference in New Issue
Block a user